This is what's planned for proof, along with what's done so far. It changes as we go, so it's a good idea to check it before starting on something big.
- 2026-09-30: the first version, with the core checks (
describe, unknown ops, sessions,eval,stdinand the wire format), server profiles and a daily compatibility matrix for nREPL, Babashka, ClojureCLR, Basilisp, jank and dialtone. The profile for repartee came a day later. - 2026-10-07:
proof proxyfor checking what clients send (#1). - 2026-10-08:
proof servefor testing clients and-likefor acting like a whole server (#2, #3), client profiles for CIDER, Calva, Conjure and vim-fireplace (#4, #6) and-record(#5). - 2026-10-09: nREPL 1.8.0 as the reference (#7).
- 2026-10-10: client profiles for REPLy and neorepl (#8).
The first release, which came out on 2026-10-26. Server authors can
run a fixed version of proof in their CI now (jank is already looking
into this, see jank#1104),
and it covers the rest of what every editor sends: interrupt,
load-file, lookups and completions, plus requests that go wrong.
- Done:
wire.error-terminalno longer fails Babashka for a message with nothing butchanged-namespacesthat arrives aftereval-error. The clients it names (REPLy and rebel-readline) lose only output, values andneed-inputthere, so that's what it looks for now. - Done:
proof run babashkaandproof proxy babashkawork, just likeproof serve -like babashka, as the profiles are embedded in the binary. People who install proof withgo installdon't have theprofilesfolder at all. - Done:
proof run profiles/babashka.toml -only 'eval.*'works, as flags can come after the profile (and after the scenarios ofproof serve). - Done:
proof run -hsays how to useproof run, rather than Go's bare "Usage of run:", and the same goes forproxyandserve.
- Done:
proof versiontakes the version from the build info, so a binary installed withgo install ...@v0.1.0knows its version. - Done: a CHANGELOG.
- Done: binaries for Linux, macOS and Windows on every release, so the CI of a server doesn't need Go. The Release workflow builds them when a version gets tagged.
- Done: a GitHub Action, so a server's workflow needs nothing but
uses: nrepl/proof@v0.1.0and the path to its profile. - Done: the CI section of Usage uses the release instead
of
@latest.
- Done: checks for interrupting a running eval, with and without
interrupt-id(Conjure never sends one), theinterruptedstatus, an idle session, aninterrupt-idthat doesn't match and the session working afterwards. - Done: the evals waiting behind an interrupted one, which nREPL 1.8.0
and Babashka drop
(nrepl#503), and where an
interrupted eval's
donegoes when the interrupt comes from another connection, which nREPL's main branch gets right now (nrepl#498). The exception of an interrupted eval, which nREPL sends after itsdone(nrepl#506), iswire.after-done's warning. - Done:
proof serveinterrupts like dialtone and repartee do, and has nREPL's bugs as scenarios (late-exception,drop-queuedandinterrupt-elsewhere), which-like clojureand-like babashkaturn on. - Not done: an interrupt sent right after its eval, which can find nREPL's session idle (nrepl#504). That's a race, so a check can't count on hitting it.
- Not needed: a step option for client profiles that sends a request
without waiting for its reply. The
interruptrequests of CIDER, Calva and vim-fireplace are plain enough forinterrupt.running, and Conjure's forinterrupt.no-id.
- Done: checks for the value of
load-fileand for a load that fails, where CIDER needseval-error, Calvaexand Conjureerr, plus what CIDER, Calva and Conjure send to load a file. The spec and the servers don't agree on which field has the contents of the file (spec#3), but every server in the matrix takesfileand passes them all.
- Done: checks for nREPL's
completionsandlookupand cider-nrepl'scomplete,infoandeldoc, for servers that list them, sending CIDER'sprefixandsymand thesymbolof Calva, Conjure and vim-fireplace. The checks ofcompletionsandlookupskip on servers that havecompleteandinfo, as clients use those then. Babashka, Basilisp and ClojureCLR don't sayno-infofor a symbol that doesn't exist, Basilisp counts columns from 0 and ClojureCLR'sfileisn't a URI, which Calva needs to jump to a definition. - Done:
proof servehas nREPL'scompletionsandlookup. - Not done: scenarios for cider-nrepl's ops in
proof serve, so-likecould act like Babashka, Basilisp and ClojureCLR there too. - spec#9 (
arglists-strandno-info) should be settled by then.
- Done: frames that aren't requests (the server has to keep taking
connections), fields of the wrong type
(nrepl#477), a client that
goes away in the middle of an eval
(babashka#2227) and
an eval in one session holding up the others
(jank#1022). A bencode
string takes jank down, and after a client goes away in the middle of
an eval, nREPL (1.8.0 and its main branch) never sends the
doneof the next eval in that session. - Not done: an eval whose reply bencode can't carry, e.g. a boolean (babashka#2201), as there's no telling which code makes a server send one.
- CI is green and the binaries build for every platform.
- nREPL passes every check with the
failseverity, and the matrix makes sense for every server in it. - Every new check has a quirk in the fake server,
proof servepasses the new checks and it has scenarios for the servers that do things differently. - Spec Changes has everything the new checks found.
- The docs cover the new checks and the release.
The second release, which came out on 2026-11-03. The compatibility
matrix has a page of its own now, with nbb and let-go in it, and there
are client profiles for clojure-cli.repl and bb repl --connect.
- Done: the Compatibility workflow publishes the matrix on
GitHub Pages, with the version of
each server, which comes from the new
versionsnippet.proof matrix -htmlbuilds the same page out of any reports. - Done: nbb and let-go, and scenarios for what they do differently in
proof serve. Neither sayseval-errorwhen the code throws or sends what it prints to stderr, nbb stops taking connections after a frame that isn't a dict, and let-go shares the current namespace between sessions and doesn't listinterruptindescribe(even though it has it).
- Done: clojure-cli.repl,
the new client of the Clojure team. It's meant for the server that
comes with it, but it works with others too. As of 0.2.3 it still
doesn't answer
need-input, so code reading input hangs, and it never closes its session. - Done:
bb repl --connect, which every server in the matrix gets right.
This is what's next for proof.
- shadow-cljs.
- The client in
nrepl.cmdline, which expects an exact list of statuses when interrupting an idle session. - vim-iced and rebel-readline.
- CIDER's integration tests jack in to nREPL, Babashka, Basilisp, nbb
and shadow-cljs. A test that connects to
proof serveinstead, with a few-likeservers andbyte-writes, would catch problems with other servers before users run into them. - neat, mezcaml and neorepl should do the same.
- The pull requests for the spec based on proof's findings, spec.nrepl.org#6-#9. The fixes for nrepl-beam, neat and mezcaml got merged on 2026-10-02, except for nrepl-beam#2, which was closed when the branch it was based on went away and has to be opened again.
- Issues for the spec about the rest of Spec Changes, once the spec pull requests are settled.
- nREPL: a release with
nrepl#498, then
nrepl#477 and
nrepl#183, which has the
same cause as #498. The next eval after a client goes away in the
middle of one loses its
donefor the same reason as nrepl#509. Babashka has the same problem, which is why it failsrobust.disconnectin a full run, but not on its own. - CIDER and Calva accepting
opsas a list, after whichdescribe.ops-dictcan allow both formats. - Reported on 2026-10-29:
basilisp#1356
(no
no-infofor unknown symbols), basilisp#1357 (columns from 0), jank#1169 (a request that throws stops its connection from answering), conjure#802 (nointerrupt-idininterrupt) and cider#4224 (async eldoc ignoresno-eldoc). - ClojureCLR doesn't say
no-infofor unknown symbols either, but clr.tools.nrepl takes bug reports on Ask Clojure rather than GitHub. - Calva waits for an eval of
java.versionin the main session before it interrupts, so it looks like it can't interrupt an eval there. That needs a run in VS Code before it gets reported.
- Incorporating Spec Changes into the spec, so that the spec and proof agree and proof can eventually be versioned together with the spec.