An nREPL server implementation for Steel Scheme www.tomwaddington.dev/steel-helix-first-steps.html
steel-scheme steel nrepl server

Files
README.md

nrepl-steel #

An nREPL server for the Steel Scheme runtime.

The protocol, transport and dispatch layers are pure Scheme; the evaluation backend is a native Rust dylib (libnrepl_steel_engine) loaded over Steel’s FFI, which owns one Steel engine per session and exposes eval plus the global symbol table that completions/lookup need.

Status #

Working server covering the operations editors depend on:

Op Notes
clone new session, an isolated Steel engine with a persistent env
close tear the session down
describe advertises supported ops + versions
eval form-by-form, one value per form, batched out/err
load-file evaluate the file field (file contents, per spec)
interrupt best-effort, queued-only (see caveat)
ls-sessions list active sessions
lookup doc / arglists / type for a symbol (alias info)
completions prefix completion over the session’s bound globals

Each session is an isolated Steel engine; definitions persist across evals within a session.

Interrupt caveat: cancellation is best-effort. A still-queued eval is dropped, but an eval already running cannot be aborted.

Installation #

Requires Steel 0.8.3 (steel on PATH) and Forge (forge on PATH).

The evaluation backend is a native dylib: forge fetches a prebuilt one per platform, or you build it yourself from a checkout with a Rust toolchain.

# From the repository – forge fetches the prebuilt dylib for your platform:
forge pkg install --git https://github.com/waddie/nrepl-steel

# Then add ~/.steel/bin to your PATH:
export PATH="$HOME/.steel/bin:$PATH"

This makes nrepl-steel available as a command and lets any Scheme script load the library with (require "nrepl-steel/nrepl-server/server.scm").

From a local checkout you must build + install the dylib yourself (it goes to $STEEL_HOME/native, default ~/.steel/native). Run forge install first: it downloads the latest release's dylib over whatever is there, so ./build.sh has to come after it.

forge install /path/to/nrepl-steel
./build.sh                  # cargo build --release + install libnrepl_steel_engine

Usage #

nrepl-steel                         # listens on 127.0.0.1:7888
nrepl-steel 127.0.0.1:9000          # or pass host:port
nrepl-steel --no-port-file          # don't write .nrepl-port

Or from a checkout, without installing:

steel nrepl-steel.scm               # listens on 127.0.0.1:7888
steel nrepl-steel.scm 127.0.0.1:9000

It prints the listen address and parks until interrupted (Ctrl-C).

The .nrepl-port file #

On a successful bind the server writes the port to .nrepl-port in the current directory. This is the convention nREPL tooling uses to find a running server without being told its port: clients search the working directory and its ancestors. Clients that rely on it, such as nautilos and CIDER, cannot reach the server without it. Pass --no-port-file to suppress the write.

The file is not removed on shutdown. Steel exposes no signal handler, so a Ctrl-C’d server never gets to clean up and leaves the file behind.

License #

Copyright © 2026 Tom Waddington

Distributed under the MIT License. See LICENSE file for details.