Protocol Reference

REPLy uses a simple newline-delimited JSON protocol over TCP (or Unix socket). Each message is one JSON object per line. This page is the complete reference for the request/response contract.

Request Envelope

Every request is a flat JSON object. Required fields:

FieldTypeDescription
opstringOperation name (e.g., "eval", "new-session")
idstringClient-assigned request ID, echoed in every response

Optional fields (not all ops use all fields):

FieldTypeDescription
sessionstringName alias or UUID of the target named session
codestringJulia code to evaluate (for eval)
namestringSession name alias (for session ops)

Keys must be kebab-case. Nested values and snake_case keys are rejected.

Example:

{"op": "eval", "id": "req-1", "session": "main", "code": "x = 42"}

Response Stream

Each request produces a stream of response messages, all with the same "id". The stream is terminated by a message containing "done" in the "status" array.

Success Response

A successful eval produces zero or more output messages, then a value message, then done:

Request:

{"op": "eval", "id": "demo-1", "code": "println(\"hello\"); 1 + 1"}

Response stream:

{"id": "demo-1", "out": "hello\n"}
{"id": "demo-1", "value": "2", "ns": "##EphemeralSession#1"}
{"id": "demo-1", "status": ["done"]}

Response message fields:

FieldTypeWhen present
idstringAlways — echoes the request id
outstringOne or more stdout chunks before the final value
errstringStderr chunk (from @warn, etc.) — not a terminal error
valuestringrepr() of the evaluated expression
nsstringModule name the eval ran in
statusarrayTerminal message only — contains "done"

Error Response

A runtime error produces a single message with both "error" and "done" in the status array:

Request:

{"op": "eval", "id": "demo-err", "code": "missing_name + 1"}

Response:

{
  "id": "demo-err",
  "status": ["done", "error"],
  "err": "UndefVarError: `missing_name` not defined",
  "ex": {
    "type": "UndefVarError",
    "message": "UndefVarError: `missing_name` not defined"
  },
  "stacktrace": [
    "top-level scope at REPL[1]:1",
    "..."
  ]
}

Error response fields:

FieldTypeDescription
statusarrayAlways contains "done" and "error"
errstringHuman-readable error message
exobjectStructured exception with type and message
stacktracearrayArray of stack frame strings

Client-side pattern — always check status before using value:

status = get(response, "status", String[])
if "done" in status
    if "error" in status
        println("Error: ", get(response, "err", "unknown error"))
    else
        println("Result: ", get(response, "value", ""))
    end
end

Status Flags

The "status" field is an array that may contain multiple flags. A message is terminal when it contains "done". Clients must tolerate unknown flags (forward compatibility).

FlagMeaning
"done"Terminal — stream is complete
"error"Eval or protocol error occurred
"unknown-op"The requested op is not supported
"session-not-found"Named session does not exist
"session-already-exists"Named session already exists (for clone)
"session-limit-reached"Server-wide session cap reached
"not-supported"Feature exists in spec but not yet implemented
"path-not-allowed"File path rejected by server allowlist (load-file)

Session Operations

See How-to: Manage Sessions for full examples. Quick reference:

OpRequired fieldsOptional fieldsReturns
new-sessionnamesession (UUID), name
ls-sessionssessions (array)
clonenamesession (source), typenew-session (UUID), session, name
closesessionbare done

Core Operations

Beyond eval and session management, REPLy provides several operations for introspection and code navigation.

describe

Returns server capabilities, supported operations, and versions.

Request:

{"op": "describe", "id": "desc-1"}

Response:

{
  "id": "desc-1",
  "ops": {
    "eval": {"doc": "...", "returns": ["out", "err", "value", "ns"]},
    "complete": {"doc": "...", "requires": ["code", "pos"], "returns": ["completions"]},
    "..."
  },
  "versions": {"julia": "1.10.0", "reply": "0.1.0"},
  "encodings-available": ["json"],
  "encoding-current": "json",
  "status": ["done"]
}

load-file

Loads and evaluates a Julia source file in the target session. Requires a server-side allowlist for security.

Request:

{"op": "load-file", "id": "load-1", "file": "/path/to/script.jl", "session": "main"}

interrupt

Interrupts an in-flight evaluation in a named session.

Request:

{"op": "interrupt", "id": "int-1", "session": "main"}

Response:

{"id": "int-1", "interrupted": ["main"], "interrupted-id": 42, "status": ["done"]}

complete

Returns tab-completion candidates for a given code string and cursor position.

Request:

{"op": "complete", "id": "comp-1", "code": "Base.prin", "pos": 9}

Response:

{
  "id": "comp-1",
  "completions": [
    {"text": "print", "type": "Function"},
    {"text": "println", "type": "Function"}
  ],
  "status": ["done"]
}

lookup

Returns documentation and method information for a symbol.

Request:

{"op": "lookup", "id": "look-1", "symbol": "println"}

Response:

{
  "id": "look-1",
  "found": true,
  "name": "println",
  "type": "Function",
  "doc": "println([io::IO], xs...)\n\nPrint and then a newline...",
  "methods": ["println(xs...) in Base at coreio.jl:4", "..."],
  "status": ["done"]
}

stdin

Sends input to a session that is currently blocked on a stdin read (e.g., readline()).

Request:

{"op": "stdin", "id": "in-1", "session": "main", "stdin": "user input\n"}

Malformed Input

If the server receives a line that is not valid JSON, it closes the connection without sending any protocol response. This is intentional — there is no error message to echo an id from.


Ordering Guarantees

Within a single request stream:

  1. out / err chunks appear before the terminal value
  2. value appears before done
  3. Exactly one done is emitted per request

Responses from concurrent requests may interleave on the wire. Clients must use the id field to demultiplex.