Skip to content

API Reference

JSON-RPC 2.0 protocol

Over the socket, each line is one JSON-RPC 2.0 message, newline-delimited. All requests must carry an id (notifications are not supported), and params must be an object.

Methods overview

methodparamsresult (success)
pty/read{ top? | bottom? | start?+end? }{ screen, cursor, size }
pty/write{ action }{ written }
pty/wait{ match?, timeout? }{ matched, screen, cursor, size, waitedMs }
pty/status{}{ running, exitCode, pid }
pty/resize{ cols, rows }{}
pty/kill{}{}

pty/status — query session status

jsonc
→ {"jsonrpc":"2.0","method":"pty/status","params":{},"id":1}
← {"jsonrpc":"2.0","result":{"running":true,"exitCode":null,"pid":1234},"id":1}
  • running: boolean, whether the session is running.
  • exitCode: number | null, the exit code if it has exited, otherwise null.
  • pid: number, the pid of the hosted process.

pty/read — read the current screen

jsonc
→ {"jsonrpc":"2.0","method":"pty/read","params":{},"id":2}
← {"jsonrpc":"2.0","result":{"screen":"root@host:~$\n","cursor":{"row":1,"col":14},"size":{"cols":100,"rows":30}},"id":2}
  • screen: string, the plain text of the current terminal screen (ANSI control sequences removed, trailing spaces trimmed per line, multiple lines joined with \n). Semantically the terminal's current actual screen, not a history log.
  • cursor: object, the cursor position, where row/col are 1-based.
  • size: object, the terminal size { cols, rows }.

pty/read supports selecting a subset of the current screen. top/bottom and start+end are two mutually exclusive sets:

jsonc
→ {"jsonrpc":"2.0","method":"pty/read","params":{"top":3},"id":3}
→ {"jsonrpc":"2.0","method":"pty/read","params":{"bottom":3},"id":4}
→ {"jsonrpc":"2.0","method":"pty/read","params":{"start":2,"end":5},"id":5}
  • top: N — take the top N lines.
  • bottom: N — take the bottom N lines.
  • start/end — take the 1-based closed interval [start, end]; they must be given together.
  • Validation: top/bottom are mutually exclusive; start/end must be given as a pair; the two sets cannot be mixed; out-of-range values are clamped automatically.

pty/write — write data

action is a single action object or an array of actions:

jsonc
→ {"jsonrpc":"2.0","method":"pty/write","params":{"action":{"text":"echo hello"}},"id":6}
← {"jsonrpc":"2.0","result":{"written":11},"id":6}

→ {"jsonrpc":"2.0","method":"pty/write","params":{"action":{"key":"Enter"}},"id":7}
← {"jsonrpc":"2.0","result":{"written":1},"id":7}

→ {"jsonrpc":"2.0","method":"pty/write","params":{"action":[{"text":"ls"},{"key":"Enter"}]},"id":8}
← {"jsonrpc":"2.0","result":{"written":5},"id":8}
  • Inside action, text and key are mutually exclusive and cannot be given together; an empty object or an empty array is rejected.
  • written: number, the actual number of UTF-8 bytes written (an array action returns the total).

Key names supported by write (action.key, case-sensitive):

CategoryKey names
DirectionArrowUp ArrowDown ArrowLeft ArrowRight
EditingEnter Tab Backspace Delete Home End PageUp PageDown Insert Escape Space
FunctionF1F12
ComboCtrl+letter (Ctrl+ACtrl+Z), Shift+letter, Alt+letter, Alt+Enter, Ctrl+Enter, Ctrl+Space, etc., modifiers can be combined (e.g. Ctrl+Alt+Del)

A single-character text can be written directly with the text field; an unresolvable key returns the -32602 invalid-params error.

pty/wait — wait for a piece of output to appear

jsonc
→ {"jsonrpc":"2.0","method":"pty/wait","params":{"match":"hello","timeout":6000},"id":9}
← {"jsonrpc":"2.0","result":{"matched":true,"screen":"hello\n","cursor":{"row":2,"col":1},"size":{"cols":100,"rows":30},"waitedMs":45},"id":9}
  • Matches match by substring against the current screen; when no match is given, it simply waits a fixed duration according to timeout.
  • timeout: the maximum wait in milliseconds, default 10000.
  • matched: boolean, whether the match happened before the timeout.
  • screen: the current screen at the moment of match or timeout.
  • waitedMs: the actual elapsed time in milliseconds.

pty/resize — resize the terminal

jsonc
→ {"jsonrpc":"2.0","method":"pty/resize","params":{"cols":120,"rows":40},"id":11}
← {"jsonrpc":"2.0","result":{},"id":11}

pty/kill — terminate the session and close the endpoint

jsonc
→ {"jsonrpc":"2.0","method":"pty/kill","params":{},"id":12}
← {"jsonrpc":"2.0","result":{},"id":12}

After issuing pty/kill, the session is terminated, the endpoint is closed, the service process exits, and the current connection is closed by the server.

Error responses

jsonc
→ {"jsonrpc":"2.0","method":"pty/unknown","params":{},"id":13}
← {"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found: pty/unknown"},"id":13}

→ {"jsonrpc":"2.0","method":"pty/write","params":{"action":{"text":"x","key":"Enter"}},"id":14}
← {"jsonrpc":"2.0","error":{"code":-32602,"message":"write 动作内 text 与 key 只能二选一"},"id":14}
  • An error object has the shape { code, message, data? }; see the table below for code/message.
  • Responses to normal requests echo the request's id; unparseable messages (where even the id cannot be extracted) return id: null.

Error codes

codeMeaning
-32700Parse error (invalid JSON)
-32600Invalid request (malformed structure / legacy {op} protocol rejected / missing id)
-32601Method not found
-32602Invalid params (e.g. text/key mutually exclusive, top/bottom mutually exclusive, unknown key name)
-32603Internal error
-32000Server error

Programmatic API (TypeScript)

createSocketPty

typescript
import { createSocketPty } from "@ai-zen/socket-pty";

const server = createSocketPty({
  endpoint: { type: "unix", path: "/tmp/v.sock" }, // or { type:"tcp", port:5174, host:"127.0.0.1" }
  command: "bash", // on Windows use "powershell.exe" / "cmd.exe"
  cols: 100,
  rows: 30,
  cwd: "/path/to/workdir", // optional
});
const address = await server.listen();

endpoint is required; the address is specified by the caller.

PtyServer instance methods

MethodDescription
listen(): Promise<string>Listen on the endpoint and create the session; returns the connection address
address(): stringThe actual listening address
session(): IPtySession | nullThe current session
close({ kill? }): Promise<void>Close the endpoint (terminates the session when kill: true); idempotent

Session object methods

server.session returns an IPtySession, providing synchronous screen-reading and other capabilities:

typescript
const session = server.session;
await session?.readScreen();                       // whole screen
await session?.readScreen({ bottom: 5 });          // bottom 5 lines
await session?.readScreen({ start: 2, end: 6 });   // lines 2..6
Method / propertyDescription
readScreen(sel?)Read the current screen, returns { screen, cursor, size }
wait(opts)Wait for output, returns { matched, screen, cursor, size, waitedMs }
write(data): numberWrite raw data, returns the UTF-8 byte count
resize(cols, rows)Resize
kill(signal?)Terminate
pid / running / exitCodeProcess info

Types and protocol exported from the main entry

The main entry @ai-zen/socket-pty also exports the following (reused by script end-to-end tests and protocol construction):

  • Types: IPtyLike, IPtySession, ReadResult, ScreenSelection, TermCursor, TermSize, WaitResult, PtyServerOptions, SocketEndpoint, PtySessionOptions, XtermScreenOptions, XtermTerminal.
  • Protocol constants/utilities: JsonRpcErrorCode, JsonRpcErrorMessage, Methods, JSONRPC, makeRequest, makeResult, makeError, parseRequest, encodeRequest, resolveKey, resolveAction, methodToOp.
  • Renderer: XtermRenderer, createRenderer.

CLI options (socket-pty serve)

OptionDescription
--cmd <command>The command to host (required). On Windows the .exe suffix is needed, e.g. powershell.exe / cmd.exe
--socket <path>Unix domain socket listen path (choose one with --port; one is required)
--port <port>TCP listen port, a concrete port in 1-65535 (choose one with --socket; one is required)
--cols <n>Terminal columns (default 100)
--rows <n>Terminal rows (default 30)
--cwd <path>Working directory
-h / --helpHelp

--socket and --port are mutually exclusive and cannot be given together; if neither is given, or --port is not a concrete port in 1-65535, serve errors out.

The CLI also provides a socket-pty mcp subcommand to start the MCP manager (see MCP Adapter).

MIT / ISC License