REPLy.jl
This project is entirely LLM-generated code. It has not been manually reviewed or audited. Use at your own risk.
REPLy.jl is a network REPL server for Julia. It exposes a Julia session over a socket-based protocol (newline-delimited JSON), allowing editors, IDEs, and other tooling to connect, evaluate code, and inspect results interactively — similar to nREPL for Clojure.
See also: Status for current implementation details and spec conformance, and API for the Julia API reference.
Installation
You can install REPLy.jl using Julia's package manager:
using Pkg
Pkg.add("REPLy")Quick Start
1. Start the Server
Start a REPLy server on a local port (default is 5555):
using REPLy
# Start a server on 127.0.0.1:5555
server = REPLy.serve(port=5555)
println("REPLy listening on port $(REPLy.server_port(server))")
# Keep the Julia process alive
wait(Condition())For a much smoother workflow, you can configure REPLy to start automatically in every interactive session. See How-to: REPLy as a Global Dev Tool.
2. Connect and Evaluate Code
Clients communicate with REPLy by sending newline-delimited JSON messages over TCP.
You can test this from a terminal using nc (netcat):
printf '%s\n' '{"op":"eval","id":"demo-1","code":"println(\"hello\"); 1 + 1"}' | nc 127.0.0.1 5555You will receive a stream of JSON responses. REPLy forwards standard output, the evaluated result, and a final done status:
{"id":"demo-1","out":"hello\n"}
{"id":"demo-1","value":"2","ns":"##REPLySession#..."}
{"id":"demo-1","status":["done"]}Every eval request runs in a fresh, isolated session — variables do not persist between requests. For persistent state across evals (editor integration, REPL workflows), see How-to: Manage Sessions.
Error Handling
If a runtime error occurs during evaluation, REPLy catches it and returns a structured error response, including the stacktrace:
printf '%s\n' '{"op":"eval","id":"demo-err","code":"missing_name + 1"}' | nc 127.0.0.1 5555See Protocol Reference for the full error response shape and all status flags.
Graceful Shutdown
Call close(server) to stop the server. By default, REPLy allows up to 5 seconds for in-flight client tasks to finish before abandoning them. You can adjust the budget:
using REPLy
server = REPLy.serve(port=5555)
# Shut down with a 10-second grace window
Base.close(server; grace_seconds=10.0)Security Model
REPLy is a local developer tool — it carries no built-in authentication. Any client that can reach the server can execute arbitrary Julia code in your process.
Default TCP binding (host=ip"127.0.0.1") listens only on the loopback interface, so only processes on the same machine can connect. If you override host to a non-loopback address, REPLy will log a startup warning.
For multi-user machines or any situation where you want OS-level access control, use a Unix domain socket instead of TCP:
server = REPLy.serve(socket_path="/tmp/reply-$(getpid()).sock")Unix sockets are created with chmod 600 (owner read/write only), so only your own processes can connect.
Do not expose a REPLy TCP server on a network-facing interface without an external access-control layer (firewall rule, VPN, SSH tunnel). There is no password, token, or TLS support in v1.x.
Resource Limits
REPLy enforces two configurable safety limits that protect against runaway clients or evaluations.
Inbound message size
Messages larger than DEFAULT_MAX_MESSAGE_BYTES (1 MiB) are rejected with a structured error and the connection is closed. To change the limit:
using REPLy
server = REPLy.serve(port=5555, max_message_bytes=512_000) # 512 KiBOversized messages produce a MessageTooLargeError internally; clients receive a plain error response.
Output truncation
Evaluation results larger than DEFAULT_MAX_REPR_BYTES (10 KB) are truncated before being sent to the client. Truncated output is suffixed with OUTPUT_TRUNCATION_MARKER ("…[truncated]"). To change the limit, pass a custom REPLy.EvalMiddleware to serve:
The middleware keyword replaces the entire default stack, which includes session, session-ops, describe, interrupt, stdin, eval, and unknown-op handlers. Passing only [SessionMiddleware(), EvalMiddleware()] silently drops all other handlers.
To customise a single element, build from the default stack and swap the target entry:
using REPLy
stack = REPLy.default_middleware_stack()
idx = findfirst(m -> m isa REPLy.EvalMiddleware, stack)
stack[idx] = REPLy.EvalMiddleware(; max_repr_bytes=100_000)
server = REPLy.serve(port=5555, middleware=stack)REPLy.default_middleware_stack, REPLy.SessionMiddleware, and REPLy.EvalMiddleware are lower-level embedding APIs rather than part of the minimal exported API surface.
Next Steps
The nc example above is useful for exploration. For persistent editor integration — where you keep a connection open and eval code on demand — copy the ready-to-use client recipe from the Tutorial: Building a Custom Client.
Development and Testing
If you are developing REPLy.jl or want to run the test suite:
- Run Automated Tests:
just test - Run Smoke Tests:
just smoke-test(starts a temporary server, exercises anevalrequest, checks error paths, and verifies malformed JSON handling).