For more than a decade the Clojure REPL most people saw in a terminal wasREPLy, the one behind lein repl. Itserved us well, but it’s showing its age, and I kept wishing for a terminalREPL that felt like CIDER, without the Emacs part. So I finally built one.neorepl 0.1 is out today!Why another REPL?There’s no shortage of Clojure REPLs, so it’s fair to ask. Here’s what I wasafter: nREPL all the way down. neorepl only speaks nREPL, so it works with anythingthat runs an nREPL server: Clojure, babashka, shadow-cljs, Basilisp,ClojureCLR and so on. The smarts live on the server. When cider-nrepl isthere neorepl uses it, the same way CIDER does, and when it isn’t it fallsback to nREPL’s built-in ops, and then to evaluating a bit of code. A REPL that’s pleasant to use: a proper line editor, highlighting,completion, arglists as you type, pretty printing, history per project anda Ctrl-C that actually interrupts the evaluation. A CLI that’s just as good for scripts and coding agents. Every lookup theREPL can do is also a command, with structured output and exit codes thatmean something. Something small and modern. Clojure 1.10+, nREPL and JLine 4 are the onlydependencies, and the same code runs on the JVM and on babashka. The wholething is about 3,300 lines right now, and I’d like to keep it that way.rebel-readline and bb repl --connect are both great, and I borrowed fromthem freely, but neither tries to be an nREPL-first tool with CIDER’s tooling,jack-in and a CLI for agents. That combination is the whole point of neorepl.For humansHere’s the REPL in action:A few things worth pointing out: Enter only submits the input once its forms are complete, so pasting a wholefunction just works. TAB completes, with the candidates’ types next to them, and the arglist ofthe function you’re calling shows up after the cursor. Values get pretty printed on the server and highlighted on the client. Commands start with a comma, the CIDER way: ,doc, ,source, ,apropos,,macroexpand, ,pst, ,reload, ,edit (which opens a definition in your$EDITOR) and ,help for the rest. The Clojure reader sees a comma aswhitespace, so they can’t clash with real code. Ctrl-C interrupts what’s running, and code that reads *in* gets its input,something REPLy never quite got right.Without a server to connect to, neorepl starts one for the project, the wayCIDER’s jack-in does, with cider-nrepl on the classpath, and stops it when youexit. It knows Leiningen, the Clojure CLI, babashka and shadow-cljs projects.ClojureScript works too. Start a ClojureScript REPL in the session (throughshadow-cljs or piggieback, which jack-in adds for you) and neorepl followsalong: evaluation, completion, docs and the rest switch to ClojureScript, and:cljs/quit takes you back.For agentsCoding agents are surprisingly good at Clojure, as long as they have a REPLto talk to. Most of them drive CLIs much better than anything else, so neoreplhas a CLI that’s meant to be driven: neorepl eval evaluates code on the project’s server. Calls share asession, so *ns*, *1 and *e carry over from one call to the next, and--session keeps separate lines of work apart. --format json (or edn) gives you the values, the output and thenamespace as data. --timeout interrupts the evaluation before giving up, so an infinite loopdoesn’t take the server down with it, and --max-output keeps a stray(range) from eating the agent’s context. neorepl check finds unbalanced parens, brackets and braces without aserver. That’s the most common way for an agent (or a human) to break aClojure file. neorepl doc, source, apropos, complete, where, macroexpand andreload do what the REPL’s commands do. neorepl server starts a server that stays up, for editors, agents andneorepl eval to share.The exit codes are boring on purpose: 0 when all went well, 1 for anevaluation error, 3 when there’s no server to talk to and 124 for a timeout(like timeout(1)).Playing nicely with nREPLA new client is also a new way to break servers, or to be broken by them, andthe nREPL world has quite a few servers these days. Fortunately I’ve beenworking on proof, a compatibility suite fornREPL, which made neorepl a good test subject.proof checks both sides of the conversation. proof proxy sits between aclient and a server and grades everything the client sends: every request hasan id, need-input gets answered with stdin in the right session, and so on.proof serve is a small nREPL server that can behave like other servers invery specific ways - sending only the last value of the code like Basilisp andjank, dropping stderr, having no interrupt op, splitting output into onemessage per character, and so on. I ran neorepl’s REPL and CLI through both,against nREPL, babashka, Basilisp and jank, and through every quirk proofserve knows about.neorepl came out of it in decent shape, but not unscathed: Code read from stdin (neorepl eval -) that then read *in* itself crashedneorepl and left the evaluation waiting on the server for input that wasnever coming. neorepl’s errors could leave the shell’s prompt dangling at the end of aline with servers that don’t end their error reports with a newline (hello,jank!). neorepl eval exited with 1 when it lost the server, which is the statusfor code that failed.All of those are fixed in 0.1. It also turned up a couple of things that arenREPL’s fault rather than neorepl’s: need-input and the end of aninterrupted evaluation can go to the wrong connection when a session is usedfrom more than one. Those will be fixed in nREPL itself.It works the other way around too. proof now checks servers with the exactrequests neorepl sends while starting its REPL and evaluating code, next tothe ones CIDER, Calva, Conjure, vim-fireplace and REPLy send, so a server thatbreaks neorepl finds out from proof, not from a bug report. nREPL, babashka,Basilisp and jank all pass those checks today.Making the neighbours betterBuilding neorepl turned up a few problems elsewhere, which is one of myfavourite side effects of writing a new client. piggieback used to evaluateonly the first form you sent it and silently drop the rest, and it loaded theClojureScript compiler at startup even when nobody asked for a ClojureScriptREPL, which added almost half a second to the startup of every server withClojureScript on the classpath. The fixes for both(piggieback#162 andpiggieback#161) will be in thenext piggieback release. The Node.jsREPL in ClojureScript itself doesn’t cope well with interrupted evaluations,and that one is next on my list.What’s next0.1 is the foundation. Here’s what I’d like to tackle next: a test runner with proper reports a full-screen inspector and stacktrace browser an MCP server and a ready-made skill for coding agents better Windows supportTry itThe easiest way to install neorepl is bbin:$ bbin install io.github.nrepl/neorepl$ cd my-project$ neoreplThe README has the details.It’s early days, so I’m sure you’ll find rough edges. Please file issues,and tell me what you’d like to see next. And if you’re one of the people whokept lein repl and REPLy going over the years - thank you! neorepl wouldn’texist without you.Keep hacking!