An nREPL client plugin for Helix, enabling interactive REPL-driven development directly in your editor.
The plugin uses a modular language adapter system that allows customization of error formatting, prompt styling, and result presentation for different nREPL implementations. Dedicated adapters for:
- Clojure/Babashka (via nrepl)
- Guile (via guile-ares-rs)
- Steel Scheme (via nrepl-steel)
- Janet (via nrepl-janet)
- Python (via nrepl-python)
With a generic fallback adapter for any other language.
Currently you’ll need Matthew Paras’s steel-event-system Helix fork to use this, and may want to check out his helix-config repo to see how to set up keybindings, etc.
This is a work in progress, experimental plugin for a work in progress, experimental plugin system. Exception handling is sparse. Testing is minimal. Edge cases have gone unconsidered. Caveat emptor.
This plugin provides the following commands:
:nrepl-connect [host:port]- Connect to nREPL server. Prompts for host if not provided, finally defaults tolocalhost:7888:nrepl-jack-in- Start nREPL server for current project and connect automatically (Clojure, Babashka, Leiningen):nrepl-disconnect- Disconnect from the server. Prompts to kill server if started via jack-in:nrepl-load-file- Load and evaluate a file (default: current buffer):nrepl-set-timeout [seconds]- Set or view evaluation timeout (default: 60 seconds):nrepl-set-orientation [vsplit|hsplit]- Set or view REPL buffer split orientation (default: vsplit):nrepl-toggle-debug- Toggle debug logging on/off:nrepl-toggle-auto-load- Toggle automatic re-loading of a source buffer into the REPL on save:nrepl-stats- Display connection and session statistics for debugging:nrepl-eval-prompt- Prompt for code to evaluate:nrepl-eval-selection- Evaluate the current selection:nrepl-eval-multiple-selections- Evaluate all selections in sequence:nrepl-eval-buffer- Evaluate the entire buffer:nrepl-interrupt- Interrupt the currently running evaluation:nrepl-stdin [text]- Send a line of stdin to the running evaluation (prompts if no text given):nrepl-lookup- Open interactive symbol lookup picker with documentation preview
All evaluation results are displayed in a dedicated *nrepl* buffer with a ns=> prompt. The *nrepl* buffer will inherit the language setting from whichever buffer you initiated the connection from, so the responses will be syntax highlighted, etc.
The lookup picker provides an interactive interface for browsing and searching available symbols with live documentation preview.
Features:
- Real-time fuzzy filtering as you type
- Displays symbol name, namespace, and type in columns
- Live documentation preview pane
- Insert symbols with or without namespace qualification
Keymap:
| Key | Action |
|---|---|
| Type characters | Fuzzy-filter symbols |
Backspace |
Remove filter character |
Up / Down |
Navigate selection (wraps around) |
Ctrl-p / Ctrl-n |
Navigate selection (vim-style) |
Tab / Shift-Tab |
Navigate selection |
Ctrl-u / Ctrl-d |
Page up/down in symbol list |
Home / End |
Jump to first/last symbol |
PageUp / PageDown |
Scroll documentation preview |
Shift-Up / Shift-Down |
Scroll documentation preview |
Enter |
Insert unqualified symbol (e.g., map) |
Alt-Enter |
Insert fully-qualified symbol (e.g., clojure.core/map) |
Escape / Ctrl-c |
Close picker |
Requirements:
- Requires
cider-nreplmiddleware for Clojure/ClojureScript - Standard
nREPL 1.5.0does not include completion/lookup operations - Example server setup:
clj -Sdeps '{:deps {nrepl/nrepl {:mvn/version "1.5.0"} cider/cider-nrepl {:mvn/version "0.58.0"}}}'\
-M -m nrepl.cmdline\
--middleware "[cider.nrepl/cider-middleware]"\
--port 7888The jack-in feature automatically starts an nREPL server for your project and connects to it.
Workflow:
# Open a file in your project
:nrepl-jack-in
# Plugin will:
# 1. Detect project files, presenting a picker if it finds multiple
# 2. Detect aliases in deps.edn files, presenting a picker if it finds multiple
# 2. Find a free port (7888-7988 range)
# 3. Start appropriate nREPL server
# 4. Write .nrepl-port file
# 5. Connect automatically
# When done:
:nrepl-disconnect
# Prompts: "Kill nREPL server? [y/n]:"
# Choose 'y' to kill server, 'n' to leave it running
Supported Project Types:
- Clojure CLI (deps.edn): Uses
clojurewith-Sdepsfor nREPL + cider-nrepl - Babashka (bb.edn): Uses
bb nrepl-server - Leiningen (project.clj): Uses
lein trampoline repl :headless
Long-running or runaway evaluations can be interrupted while they are still in flight:
:nrepl-interrupt
Interrupt is delivered to the server immediately, even while an evaluation is
parked accumulating output — it does not wait for the current evaluation to
finish. Interrupted results are marked as such in the *nrepl* buffer.
If an evaluation blocks waiting for input (e.g. a Clojure (read-line)), the
plugin detects the need-input state and prompts you for a line of input,
feeding it back to the server so the evaluation can continue. You can also send
input explicitly:
:nrepl-stdin some text # send "some text"
:nrepl-stdin # prompt for a line of input
When enabled, saving a source buffer whose language matches the active connection automatically re-loads that file into the REPL — handy for keeping the running image in sync with your edits:
:nrepl-toggle-auto-load # toggle on/off
This is off by default and only fires for buffers backed by a real file whose language matches the connected adapter (scratch buffers and unrelated languages are skipped).
By default, evaluations time-out after 60 seconds. You can adjust this:
At runtime:
:nrepl-set-timeout 120 # Set to 2 minutes
:nrepl-set-timeout # View current timeout
Set default in init.scm:
(require "nrepl.scm")
(nrepl-set-timeout 120) # 2 minute default for all sessionsBy default, the *nrepl* buffer opens in a vertical split (vsplit). You can change this:
At runtime:
:nrepl-set-orientation hsplit # Switch to horizontal split
:nrepl-set-orientation vsplit # Switch to vertical split
:nrepl-set-orientation # View current orientation
Shortcuts: v, vertical, h, horizontal also work.
Set default in init.scm:
(require "nrepl.scm")
(nrepl-set-orientation 'hsplit) # Horizontal split defaultNote on buffer visibility:
If you close the split window (i.e. with :q) but the *nrepl* buffer still exists, the next evaluation will create a new *nrepl* buffer in a split with your configured orientation rather than reopening the existing one. This ensures the orientation setting is always respected. The old buffer with its history remains accessible via the buffer picker (Space + b).
You’ll need:
- Matthew Paras’s steel-event-system Helix fork
- Rust toolchain (for building)
- An nREPL server (e.g., Clojure, Babashka, ClojureScript)
For the Forge install below you do not need the Rust toolchain — a prebuilt dylib is downloaded for your platform. The from-source routes still require Rust.
Forge is Steel’s package manager (it ships with the Steel interpreter). It fetches the plugin’s Scheme source and a prebuilt native library for your platform — no Rust build required.
forge pkg install --git https://github.com/waddie/nrepl.hxThis copies the cog to ~/.steel/cogs/nrepl.hx/ and downloads the matching
libsteel_nrepl dylib to ~/.steel/native/. Prebuilt binaries are published for
aarch64-macos, x86_64-macos, x86_64-linux and x86_64-windows; on any other
platform, use the from-source install below.
Then add to ~/.config/helix/init.scm:
(require "nrepl.hx/nrepl.scm")Reload with :config-reload, or restart Helix. See the key-bindings step below
(it applies to every install method).
1. Build Helix with Steel plugin system:
git clone https://github.com/mattwparas/helix.git -b steel-event-system
cd helix
cargo xtask steel2. Build and install nrepl.hx:
git clone https://github.com/waddie/nrepl.hx.git
cd nrepl.hx
cargo build --release
./install.shThe install script will:
- Copy the dylib/so/dll to
~/.steel/native/ - Copy
nrepl.scmto~/.config/helix/ - Copy language adapters to
~/.config/helix/cogs/nrepl/ - Provide instructions for updating
init.scm
3. Enable the plugin:
Add to ~/.config/helix/init.scm:
(require "nrepl.scm")4. Add key-bindings (optional but recommended):
Add to ~/.config/helix/init.scm:
(require "cogs/keymaps.scm")
(keymap (global)
(normal (space (n
(C ":nrepl-connect")
(D ":nrepl-disconnect")
(J ":nrepl-jack-in")
(L ":nrepl-load-file")
(S ":nrepl-stdin")
(b ":nrepl-eval-buffer")
(i ":nrepl-interrupt")
(l ":nrepl-lookup")
(m ":nrepl-eval-multiple-selections")
(p ":nrepl-eval-prompt")
(s ":nrepl-eval-selection")))
(A-ret ":nrepl-eval-selection"))
(select (space (n
(C ":nrepl-connect")
(D ":nrepl-disconnect")
(J ":nrepl-jack-in")
(L ":nrepl-load-file")
(S ":nrepl-stdin")
(b ":nrepl-eval-buffer")
(i ":nrepl-interrupt")
(l ":nrepl-lookup")
(m ":nrepl-eval-multiple-selections")
(p ":nrepl-eval-prompt")
(s ":nrepl-eval-selection")))
(A-ret ":nrepl-eval-selection")))This gives you (in both normal and select modes):
space.n.C- Connect to nREPLspace.n.J- Jack-in (start server and connect)space.n.D- Disconnectspace.n.L- Load and evaluate a filespace.n.b- Evaluate bufferspace.n.i- Interrupt the running evaluationspace.n.l- Open symbol lookup pickerspace.n.m- Evaluate multiple selectionsspace.n.p- Evaluate from promptspace.n.s- Evaluate selectionspace.n.S- Sendstdinto the running evaluationAlt + Enter- Quick evaluate selection
See helix-config for more key-binding examples.
5. Restart Helix
If you prefer manual installation or the script doesn’t work for your system:
# Build the plugin
cargo build --release
# Copy files (adjust paths for your OS)
mkdir -p ~/.steel/native ~/.config/helix ~/.config/helix/cogs/nrepl
cp target/release/libsteel_nrepl.dylib ~/.steel/native/ # or .so on Linux, .dll on Windows
cp nrepl.scm ~/.config/helix/
cp -r cogs/nrepl/* ~/.config/helix/cogs/nrepl/
# Add to ~/.config/helix/init.scm
echo '(require "nrepl.scm")' >> ~/.config/helix/init.scmAfter installation:
Option 1: Jack-In (Recommended for Clojure/Babashka/Leiningen projects)
# Open a file in your project
:nrepl-jack-in
# Plugin automatically starts server and connects
# Select some code and evaluate
:nrepl-eval-selection
# Check the *nrepl* buffer for results
# When done:
:nrepl-disconnect
# Choose 'y' to kill the server, or 'n' to leave it running
Option 2: Manual Server (For other languages or custom setups)
-
Start an nREPL server manually:
# Clojure clj -Sdeps '{:deps {nrepl/nrepl {:mvn/version "1.7.0"} cider/cider-nrepl {:mvn/version "0.59.0"}}}'\ -M -m nrepl.cmdline\ --middleware "[cider.nrepl/cider-middleware]"\ --port 7888 # Or Babashka bb nrepl-server 7888
-
In Helix:
:nrepl-connect # Enter: localhost:7888 (or press Enter for default) # Select some code and evaluate :nrepl-eval-selection # Check the *nrepl* buffer for results -
When done:
:nrepl-disconnect
I’ve written a bit of Scheme over the years, but have next to no Rust experience. Claude Code assisted heavily with the crates in this repo.
AGPL-3.0-or-later
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
