API Reference

This page is generated by Documenter.jl from docstrings. It is only useful when the docs are rendered — the raw Markdown source contains only the @autodocs directive, not the actual symbols.

To view the rendered API reference locally:

julia --project=docs docs/make.jl
# then open docs/build/api/index.html

The exported surface includes:

  • Server: serve, serve_multi, serve_mcp, server_port, server_socket_path, AbstractServerHandle, MultiListenerServer, ServerState
  • Sessions: SessionManager, get_or_create_named_session!, sweep_idle_sessions!, session_id, SessionState, SessionIdle, SessionRunning, SessionClosed
  • Transport: AbstractTransport, JSONTransport, send!, receive
  • MCP adapter: mcp_initialize_result, mcp_tools, mcp_call_tool, mcp_eval_request, mcp_ensure_default_session!, mcp_new_session_result, mcp_list_sessions_result, mcp_close_session_result, collect_reply_stream, reply_stream_to_mcp_result
  • Constants: MCP_PROTOCOL_VERSION, MCP_DEFAULT_SESSION_NAME, MCP_EPHEMERAL_SESSION, DEFAULT_COLLECT_TIMEOUT_SECONDS, DEFAULT_CLOSE_GRACE_SECONDS, DEFAULT_MAX_REPR_BYTES, DEFAULT_MAX_MESSAGE_BYTES, OUTPUT_TRUNCATION_MARKER

REPLy._interrupt_session_evalMethod
_interrupt_session_eval(session; interrupt_id=nothing) -> (interrupted, interrupted_id)

Attempt to interrupt the running eval in session.

  • interrupt_id: if provided (non-nothing), only interrupt when the running eval's ID matches. If there is a mismatch (the targeted eval already finished), returns no-op success ([], nothing).
  • Returns (interrupted::Vector{String}, interrupted_id::Union{Int,Nothing}) where interrupted contains session.name on a real interrupt and interrupted_id holds the eval ID that was interrupted (or nothing when no interrupt was sent).
source
REPLy._maybe_revise!Method
_maybe_revise!()

Call Main.Revise.revise() if Revise is loaded in Main and defines a callable revise function. Any error thrown by revise() is caught and logged with @warn — it must never abort the eval that follows.

The entire check-and-call is dispatched via Base.invokelatest so that Main.Revise bindings created after REPLy was compiled (including test mocks) are always visible regardless of the current world age.

source
REPLy._revise_if_presentMethod
_revise_if_present()

Inner implementation for the Revise hook: checks whether Main.Revise and Main.Revise.revise are defined in the current world age and, if so, calls revise().

This function is intended to be invoked via Base.invokelatest (see _maybe_revise!) so that it executes in the latest world — necessary when Revise (or a test mock) was loaded after the REPLy module was compiled.

Security: only calls revise() when Main.Revise is the authentic Revise package (verified via Base.loaded_modules). A shadow module eval'd into Main under the name Revise will not appear in Base.loaded_modules with the correct PkgId and is silently ignored.

source
REPLy.begin_eval!Method
begin_eval!(session, task)

Atomically transition session from SessionIdle to SessionRunning, assign task, and update last_active_at. Throws ArgumentError if not in SessionIdle.

Prefer this over calling transition_session_state! and _set_eval_task! separately.

source
REPLy.clamp_history!Function
clamp_history!(session, max_size=MAX_SESSION_HISTORY_SIZE)

Drop the oldest entries from session.history so it does not exceed max_size. Called after each history push.

source
REPLy.clone_named_session!Method
clone_named_session!(manager, source_id_or_name, dest_name)

Create a new named session with the alias dest_name by copying the module bindings from the session identified by source_id_or_name (UUID or alias). The clone gets its own UUID and anonymous module so mutations in the clone do not affect the original.

Returns the new NamedSession, or nothing if source_id_or_name is not found.

Throws ArgumentError if dest_name alias already exists — callers must check or close the existing session first.

source
REPLy.collect_reply_streamMethod

Collect Reply messages for request_id until the terminal done status arrives.

Messages for other request ids are buffered into pending, allowing callers to safely reuse the same transport across interleaved request streams.

If no terminal message arrives within timeout_seconds, the transport is closed and a one-element collection containing a synthetic ["done", "timeout"] terminal message is returned. A positive timeout_seconds is required.

source
REPLy.create_ephemeral_session_if_within_limit!Method
create_ephemeral_session_if_within_limit!(manager, max_sessions) -> Union{ModuleSession, Nothing}

Atomically check the total session count against max_sessions and create a new ephemeral session if below the limit. Returns nothing when the limit is already reached. The check and creation occur under a single manager.lock acquisition, preventing the TOCTOU race that exists when they are separate.

source
REPLy.create_named_session!Method
create_named_session!(manager, name; id=nothing)

Create and register a persistent named session. The session is keyed by its UUID in named_sessions and will appear in list_named_sessions output. If name is non-empty it is also registered in name_to_uuid as an alias.

Throws ArgumentError if name is non-empty and an alias with that name already exists — callers must destroy the existing session first (via destroy_named_session!) before registering a new one under the same alias. This prevents detached session objects: a caller holding a reference to the old session would otherwise still be able to mutate it after replacement.

If a session with the same id already exists it is silently replaced.

Name and id validation is the caller's responsibility. An explicit id may be supplied (for testing); otherwise a fresh UUID is generated.

source
REPLy.create_named_session_if_within_limit!Method
create_named_session_if_within_limit!(manager, name, max_sessions; id) -> Union{NamedSession, Nothing}

Atomically check the total session count against max_sessions and create a new named session if below the limit. Returns nothing when the limit is reached. Throws ArgumentError if a non-empty name alias already exists.

source
REPLy.descriptorMethod
descriptor(mw::AbstractMiddleware) -> MiddlewareDescriptor

Return the MiddlewareDescriptor for mw. The default makes no claims. Override to declare what ops a middleware provides/requires.

source
REPLy.destroy_named_session!Method
destroy_named_session!(manager, id_or_name) -> Bool

Remove the named session identified by UUID or name alias. Returns true if a session was removed, false if no such session existed. This operation is idempotent — calling it when no such session exists is safe.

Close blocks until any in-flight eval on the session completes: eval_lock is acquired before the state transition so that end_eval! can never race against a SessionClosed transition. The manager lock is released between the resolve and the eval drain to avoid holding it during a potentially long eval.

source
REPLy.destroy_session!Method
destroy_session!(manager, session)

Remove session from manager. This operation is idempotent so cleanup code can call it safely from both success and error paths.

source
REPLy.dispatch_middlewareMethod
dispatch_middleware(stack::Vector{<:AbstractMiddleware}, index::Int, msg, ctx::RequestContext)

Recursively process msg through the middleware stack starting at index. Each middleware piece can choose to forward the message to the next piece in the chain or handle it immediately and return early. The final responses are typically accumulated in ctx.emitted or returned directly.

source
REPLy.end_eval!Method
end_eval!(session)

Atomically transition session from SessionRunning to SessionIdle, clear the eval task, and update last_active_at. Throws ArgumentError if not in SessionRunning.

Prefer this over calling transition_session_state! and _set_eval_task! separately.

source
REPLy.get_or_create_named_session!Method
get_or_create_named_session!(manager, name) -> NamedSession

Return the existing named session registered under the name alias name, or atomically create and register one if absent. The check-and-create is performed under a single manager.lock acquisition to prevent concurrent callers from each creating a session and silently replacing the other's work.

source
REPLy.list_named_sessionsMethod
list_named_sessions(manager)

Return all registered persistent named sessions. Ephemeral sessions are never included — this is the authoritative source for ls-sessions.

source
REPLy.lookup_named_sessionMethod
lookup_named_session(manager, id_or_name)

Return the NamedSession registered under the given UUID or name alias, or nothing if no such session exists.

Resolution order:

  1. Try id_or_name as a UUID key in named_sessions.
  2. Try id_or_name as a name alias in name_to_uuid, then look up the UUID.
source
REPLy.mcp_call_toolMethod
mcp_call_tool(tool_name, args, manager; max_sessions=typemax(Int)) -> CallToolResult

Dispatch an MCP tools/call request to the appropriate adapter helper.

Routes session lifecycle tools (julia_new_session, julia_list_sessions, julia_close_session) to their respective lifecycle helpers. Returns a stub error for tools that are not yet implemented (julia_complete, julia_lookup, julia_load_file, julia_interrupt). Returns an error for julia_eval (which requires a live transport and is handled by the full adapter loop) and for unknown tool names.

max_sessions is forwarded to mcp_new_session_result to enforce the server session limit when creating sessions from the MCP adapter.

source
REPLy.mcp_close_session_resultMethod
mcp_close_session_result(manager, session_name) -> CallToolResult

Close the session identified by UUID or name alias and return a non-error CallToolResult. Returns an error result if the session does not exist. The existence check and removal are performed atomically via destroy_named_session!, which returns true only when it actually removed an entry.

source
REPLy.mcp_ensure_default_session!Method
mcp_ensure_default_session!(manager; name=MCP_DEFAULT_SESSION_NAME) -> String

Ensure the adapter's persistent default session exists in manager. Creates it if absent; returns the canonical UUID of the session (whether newly created or already existing). The name alias is registered so the session can also be found by name, but the UUID is the canonical identity used for routing. Thread-safe: the check-and-create is performed atomically under a single lock acquisition via get_or_create_named_session!.

source
REPLy.mcp_eval_requestMethod

Build a Reply eval request from MCP julia_eval arguments.

When session is omitted, the adapter routes to default_session. When session == "ephemeral", the Reply request omits the session field. This helper rejects invalid adapter inputs before emitting a Reply message.

source
REPLy.mcp_list_sessions_resultMethod
mcp_list_sessions_result(manager) -> CallToolResult

List all named sessions in manager and return their canonical UUIDs (with optional name aliases) as a CallToolResult. Returns "[]" when no sessions exist. Each line is "<uuid>" for unnamed sessions or "<uuid> (<name>)" for sessions that have a name alias.

source
REPLy.mcp_new_session_resultMethod
mcp_new_session_result(manager; max_sessions=typemax(Int)) -> CallToolResult

Create a new unnamed session and return its canonical UUID in a non-error CallToolResult. The UUID is the spec-compliant identity for all subsequent ops. Returns an error result when the session limit is reached.

source
REPLy.read_bounded_lineMethod
read_bounded_line(io, max_bytes) -> String

Read bytes from io up to the next newline (\n), returning the line content without the trailing newline. Throws MessageTooLargeError(max_bytes) if more than max_bytes bytes are read before a newline is found.

Unlike readline(), memory use is proportional to min(actual_bytes, max_bytes) rather than the full payload size.

source
REPLy.reply_stream_to_mcp_resultMethod

Map a complete Reply response stream to an MCP CallToolResult.

Status precedence is timeout > interrupted > error > success so terminal non-success modes produce deterministic MCP output even when Reply status arrays contain multiple flags.

source
REPLy.resolve_moduleMethod
resolve_module(module_path) -> Module or nothing

Resolve a dotted module path (e.g. "Main.Foo.Bar") by walking the module hierarchy starting from Main. Returns nothing if any segment is missing or not a Module.

Limitation: only Main-rooted paths are supported. Modules created inside a named session's anonymous module cannot be addressed via this function.

source
REPLy.serveMethod
serve(; host=ip"127.0.0.1", port=5555, socket_path=nothing, manager=SessionManager(), middleware=default_middleware_stack(), limits=ResourceLimits(), max_message_bytes=DEFAULT_MAX_MESSAGE_BYTES)

Start the REPLy JSON-RPC server. If socket_path is provided, a Unix domain socket server is created at that path. Otherwise, a TCP server is started on the given host and port.

Arguments

  • host: The IP address to listen on (default: 127.0.0.1).
  • port: The port to listen on (default: 5555).
  • socket_path: An optional path for a Unix domain socket server. Mutually exclusive with host/port.
  • manager: The SessionManager used to track state across sessions.
  • middleware: A vector of middleware handlers to process incoming requests.
  • limits: A ResourceLimits struct with server-wide resource constraints (default: ResourceLimits()).
  • max_message_bytes: Maximum allowed inbound message size in bytes. Requests exceeding this limit are rejected with a structured error response and the connection is closed (default: DEFAULT_MAX_MESSAGE_BYTES, 1 MiB).

Returns

A server handle (TCPServerHandle or UnixServerHandle) which can be closed with close(server).

source
REPLy.serve_mcpMethod
serve_mcp(; manager=SessionManager(), middleware=default_middleware_stack(), limits=ResourceLimits(), max_message_bytes=DEFAULT_MAX_MESSAGE_BYTES)

Start a stdio-based MCP server. This function blocks, reading JSON-RPC 2.0 messages from stdin and writing responses to stdout.

It automatically:

  1. Starts a background REPLy TCP server on a random loopback port.
  2. Handles the MCP initialize and tools/list handshake.
  3. Dispatches tools/call requests.
  4. Routes julia_eval to the background REPLy server.
  5. Logs internal errors and diagnostic info to stderr.

Use this as the entry point for integrating REPLy with MCP clients like Claude Desktop or VS Code extensions.

source
REPLy.serve_multiMethod
serve_multi(specs...; manager, middleware, limits, max_message_bytes)

Start multiple listeners (TCP and/or Unix domain socket) that share one session namespace and one resource-limit domain.

Each spec is a named tuple with either:

  • (; port=N) or (; host=..., port=N) for a TCP listener
  • (; socket_path="...") for a Unix domain socket listener

Returns a MultiListenerServer which can be closed with close(server).

source
REPLy.session_countMethod
session_count(manager)

Return the number of registered ephemeral sessions. Named sessions are not counted here; use length(list_named_sessions(manager)) for those.

source
REPLy.session_eval_idMethod
session_eval_id(session)

Return the monotonic eval ID for the most recently started (or currently running) eval on session. Starts at 0 (no eval has started yet); increments at the start of each eval so the running eval always has a known, stable ID. Thread-safe.

source
REPLy.session_eval_taskMethod
session_eval_task(session)

Return the Task currently evaluating in session, or nothing if idle. Thread-safe.

source
REPLy.session_idMethod
session_id(session)

Return the canonical UUID string that identifies a persistent NamedSession.

source
REPLy.session_module_nameMethod
session_module_name(session)

Return the module name for session. Always "<anonymous>" for light sessions, since they are backed by gensym'd anonymous modules.

source
REPLy.session_nameMethod
session_name(session)

Return the optional alias name for a persistent NamedSession. May be an empty string if no alias was provided at creation.

source
REPLy.sweep_idle_sessions!Method
sweep_idle_sessions!(manager; max_idle_seconds) -> Vector{String}

Destroy all SessionIdle named sessions whose last_active_at is more than max_idle_seconds seconds in the past. Running and closed sessions are skipped.

Returns the name alias of each removed session, or its UUID if the session had no alias, in the order they were swept.

Runs in three phases to avoid TOCTOU races:

  1. Snapshot session references under manager.lock (no session locks held).
  2. Check state under each session.lock alone (manager is unblocked during this).
  3. Re-acquire both locks per candidate; re-verify identity and state before destroying.

Phase 3 is necessary because a session can be recreated under the same name (invalidating identity) or transitioned to SessionRunning (invalidating state) between phases 1/2 and the actual destruction.

source
REPLy.total_session_countMethod
total_session_count(manager)

Return the total number of active sessions: ephemeral + named. Used for max_sessions enforcement.

source
REPLy.transition_session_state!Method
transition_session_state!(session, new_state)

Transition session between SessionIdle and SessionRunning. Throws ArgumentError for any other edge, including transitions to/from SessionClosed (which is terminal and reachable only through destroy_named_session!) and self-transitions.

source
REPLy.try_begin_eval!Method
try_begin_eval!(session, task) -> Bool

Attempt to atomically transition session from SessionIdle to SessionRunning, assign task, and update last_active_at. Returns true on success.

Returns false (without throwing) if the session is in SessionClosed, making this safe to call after a concurrent destroy_named_session! without a separate closed-session check.

Throws ArgumentError for SessionRunning — callers must hold session.eval_lock to prevent double-acquisition, which is the only way this state can occur here.

source
REPLy.validate_session_nameMethod
validate_session_name(name) -> Union{Nothing, String}

Return nothing if name is a valid session name, or an error message string if not. Valid names are non-empty, non-whitespace-only, match [a-zA-Z0-9_-]+, and are at most MAX_SESSION_NAME_BYTES bytes.

source
REPLy.validate_stackMethod
validate_stack(stack) -> Vector{String}

Validate a middleware stack and return a (possibly empty) list of error strings.

Checks:

  • Duplicate provides: two or more middlewares claiming the same op name.
  • Unsatisfied requires: a middleware requiring a name not provided by any earlier middleware.

Note: validate_stack is not called automatically by build_handler. Call it explicitly at server startup (or in tests) to verify a custom stack before use.

source
REPLy.with_session_evalMethod
with_session_eval(f, ctx, request_id)

Shared lifecycle wrapper used by eval_responses and load_file_responses.

Creates an ephemeral session when ctx.session is nothing, resolves the active session, then dispatches based on type:

  • NamedSession: acquires eval_lock, guards with try_begin_eval! (returning a "session was closed" error if the session was concurrently destroyed), runs f(session) under a try/finally that calls end_eval!, then releases the lock.
  • ModuleSession (ephemeral): calls f(session) directly without locking.

Destroys the ephemeral session in a finally block so cleanup is guaranteed on both success and error paths.

f receives the active session and must return a Vector{Dict{String,Any}}.

source
REPLy.AbstractServerHandleType
AbstractServerHandle

Abstract supertype for single-listener server handles. Subtypes (TCPServerHandle, UnixServerHandle) must have fields: listener, accept_task, client_tasks, clients, clients_lock, handler, middleware, closing, state.

source
REPLy.AuditMiddlewareType
AuditMiddleware(log; client_id, source_ip)

Middleware that records every request to an AuditLog. Place it first in the stack so all operations (eval, session ops, describe, etc.) are captured.

client_id and source_ip are per-connection identifiers; they default to a nil UUID and an empty string. Pass them explicitly when per-connection identity is available (e.g. from the transport layer).

source
REPLy.CompleteMiddlewareType
CompleteMiddleware

Middleware that handles op == "complete" requests. Uses Julia's built-in REPL completion engine to return candidates at the given cursor position. Out-of-range positions return an empty completions array rather than an error. All other ops are forwarded to the next middleware.

source
REPLy.DescribeMiddlewareType
DescribeMiddleware(ops_catalog)

Middleware that handles op == "describe" requests. Returns a single terminal response containing the ops catalog (built dynamically from middleware descriptors by build_handler), Julia and Reply versions, and encoding support. All other ops are forwarded to the next middleware.

Construct with no arguments for an empty catalog (useful in unit tests that only check top-level fields, versions, or forwarding). Use build_handler() to get a fully populated catalog derived from the active middleware stack.

source
REPLy.EvalMiddlewareType
EvalMiddleware(; max_repr_bytes=DEFAULT_MAX_REPR_BYTES)

Middleware that handles op == "eval" requests. Executes Julia code in the active session module with captured stdout/stderr, truncates the repr of the return value at max_repr_bytes, and returns a sequence of response messages (out, err, value, done). Passes all other ops to the next middleware.

Named sessions are serialized per session via session.eval_lock (FIFO within a session; independent across sessions). Ephemeral sessions have no cross-request state and need no serialization.

source
REPLy.HandlerContextType
HandlerContext(manager::SessionManager)

Context shared across the entire lifespan of a connection or server handler. Contains the SessionManager that tracks all active sessions.

source
REPLy.InterruptMiddlewareType
InterruptMiddleware

Middleware that handles op == "interrupt" requests. Looks up the named session specified by the session field, throws InterruptException to the eval task if one is running, and returns an interrupted array in the response.

  • Running eval: interrupted contains the session name; the eval task receives InterruptException and will terminate with status:["done","interrupted"].
  • Idle or already-completed session: interrupted is empty (idempotent).

All other ops are forwarded to the next middleware.

source
REPLy.LoadFileMiddlewareType
LoadFileMiddleware(; load_file_allowlist=nothing)

Middleware that handles op == "load-file" requests. Reads file from disk and evaluates its content in the active session module using Base.include_string so that stack traces reference the source file path and line numbers.

load_file_allowlist must be a function (path::String) -> Bool that returns true for permitted paths. When not provided, all file load requests are denied by default — pass load_file_allowlist = _ -> true to allow all files (insecure). Returning false causes the request to fail with a path-not-allowed error before any file I/O occurs, preventing path enumeration.

All other ops are forwarded to the next middleware.

source
REPLy.LookupMiddlewareType
LookupMiddleware

Middleware that handles op == "lookup" requests. Resolves the symbol field in the optional module context (defaulting to the session module or Main), returns documentation and method signatures when found, and returns "found" => false when the symbol does not exist. All other ops are forwarded.

source
REPLy.MiddlewareDescriptorType
MiddlewareDescriptor(; provides, requires, expects, op_info)

Metadata describing a middleware's interface contract used for startup validation and dynamic describe responses.

  • provides::Set{String} — operation names (e.g. "eval") this middleware handles.
  • requires::Set{String} — names that must be provided by some earlier middleware in the stack.
  • expects::Vector{String} — human-readable ordering constraints (informational; not enforced by validate_stack).
  • op_info::Dict{String, Dict{String, Any}} — per-op metadata (doc, requires, optional, returns) used to build describe responses dynamically.
source
REPLy.RequestContextType
RequestContext(manager, emitted, session, server_state)

Context associated with a single incoming request. Tracks the manager, the list of emitted responses generated so far, the session active for the request (if any), and the server_state (shared server-wide limits and counters). server_state is nothing when build_handler is called without a state argument (e.g. in unit tests that don't need limit enforcement).

source
REPLy.ResourceLimitsType
ResourceLimits(; max_repr_bytes, max_eval_time_ms, max_output_bytes, max_session_history, max_sessions, max_concurrent_evals, rate_limit_per_min, max_connections, revise_hook_enabled)

Immutable configuration struct for resource limits applied to eval requests and sessions.

Fields:

  • max_repr_bytes::Int — maximum byte length for repr output (default: DEFAULT_MAX_REPR_BYTES, 10 KB). Active: used by EvalMiddleware.
  • max_eval_time_ms::Int — maximum wall-clock eval time in milliseconds (default: 30 000). Enforced by EvalMiddleware (Phase 7C).
  • max_output_bytes::Int — maximum captured stdout/stderr bytes per eval (default: 1 000 000). Enforced by EvalMiddleware (truncates stdout and stderr independently).
  • max_session_history::Int — maximum entries in a named session's history vector (default: MAX_SESSION_HISTORY_SIZE, 1000). Enforced by _update_history! via clamp_history!.
  • max_sessions::Int — maximum total active sessions (named + ephemeral) allowed at one time (default: 100). Enforced by SessionMiddleware and SessionOpsMiddleware.
  • max_concurrent_evals::Int — maximum number of eval operations that may run concurrently server-wide (default: 10). Enforced by EvalMiddleware.
  • rate_limit_per_min::Int — maximum number of requests a single connection may send per 60-second sliding window (default: 600). Enforced by the transport layer (Phase 7B).
  • max_connections::Int — maximum number of simultaneous TCP/Unix connections (default: 100). When the limit is reached, new connections are immediately closed.
  • revise_hook_enabled::Bool — when true (default), EvalMiddleware calls Main.Revise.revise() before each named-session eval if Revise is loaded in Main. Set to false to disable the hook entirely.
source
REPLy.ServerStateType
ServerState

Shared mutable state that lives at the server level (above any individual connection). Holds the configured ResourceLimits and runtime counters that span all client sessions.

  • limits::ResourceLimits — resource limits configured at serve() time.
  • max_message_bytes::Int — maximum inbound message size (bytes).
  • active_evals::Threads.Atomic{Int} — number of eval operations currently in flight server-wide.
source
REPLy.ServerStateMethod
ServerState(limits, max_message_bytes) -> ServerState

Construct a ServerState with all counters initialised to zero.

source
REPLy.SessionLimitReachedErrorType
SessionLimitReachedError()

Thrown by clone_named_session! when the session limit is reached inside a lock, so callers can distinguish a limit hit from a missing source session without changing the function's return type.

source
REPLy.SessionManagerType
SessionManager

Track ephemeral ModuleSessions and persistent NamedSessions separately.

  • ephemeral_sessions — short-lived sessions created per eval request; session_count reflects this vector for leak detection.
  • named_sessions — persistent sessions keyed by UUID; the only sessions that appear in ls-sessions output.
  • name_to_uuid — optional alias-to-UUID index; allows callers to look up sessions by human-readable name in addition to canonical UUID.

The invariant that ephemeral sessions never appear in list_named_sessions is enforced by keeping the two registries strictly separate.

source
REPLy.SessionOpsMiddlewareType
SessionOpsMiddleware

Handle session management operations: new-session, ls-sessions, close-session/close, and clone-session/clone. These ops manipulate the named-session registry directly and never delegate to downstream middleware.

The canonical op names (per OpenSpec protocol) are "close" and "clone". The hyphenated forms "close-session" and "clone-session" are deprecated aliases kept for backward compatibility — they emit a deprecation warning when used.

This middleware must appear after SessionMiddleware in the stack so that requests carrying a "session" key for named-session routing are resolved first, and before UnknownOpMiddleware so these ops are not rejected.

source
REPLy.SessionStateType
SessionState

Lifecycle state of a NamedSession. Valid transitions via transition_session_state!:

  • SessionIdleSessionRunning (eval starts)
  • SessionRunningSessionIdle (eval completes or errors)

SessionClosed is a terminal state reached only through destroy_named_session!. No transition out of SessionClosed is possible.

source
REPLy.StdinMiddlewareType
StdinMiddleware

Middleware that handles op == "stdin" requests. Puts input text into the named session's stdin_channel, where a per-eval feeder task picks it up and writes it to the eval's redirected stdin pipe.

  • Running eval (SessionRunning): delivered contains the session name.
  • Idle session (SessionIdle): buffered contains the session name; input waits in the channel for the next eval's feeder to consume.
  • Closed or unknown session: returns an error response.

All other ops are forwarded to the next middleware.

source