Here's how the servers below fare against the checks of proof, which are mostly about what the clients people use (CIDER, Calva, Conjure, vim-fireplace, REPLy and so on) need from a server.
Hover over a check to see why it matters, and over a verdict for the details.
| Check | nREPL1.8.0 | Babashka1.13.229 | nbb1.6.214 | ClojureCLR1.12.6 | Basilisp0.5.1 | jank0.1-alpha | let-go1.13.0 | dialtone0.1.0 | repartee0.1.0 |
|---|---|---|---|---|---|---|---|---|---|
| describe | |||||||||
describe.replydescribe gets a reply | pass | pass | pass | pass | pass | pass | pass | pass | pass |
describe.ops-dictops is a dict keyed by op name | pass | pass | pass | pass | pass | pass | pass | pass | pass |
describe.required-opsdescribe lists describe, eval, clone and close | pass | pass | pass | pass | pass | fail | pass | pass | pass |
describe.versionsversions identifies the runtime | pass | pass | pass | pass | pass | pass | warn | pass | pass |
| op | |||||||||
op.unknownAn unknown op gets unknown-op | pass | pass | pass | pass | pass | pass | pass | pass | pass |
op.unknown-echoThe unknown-op reply echoes the op | pass | pass | warn | warn | warn | warn | warn | pass | pass |
| session | |||||||||
session.cloneclone returns a new session | pass | pass | pass | pass | pass | pass | pass | pass | pass |
session.persistentDefinitions persist within a session | pass | pass | pass | pass | pass | pass | pass | pass | pass |
session.across-connectionsA session can be used from another connection | pass | pass | pass | warn | warn | warn | pass | pass | pass |
session.isolatedSessions don't share state | pass | pass | fail | fail | fail | fail | fail | pass | pass |
session.ephemeralRequests without a session work | pass | pass | pass | pass | pass | pass | pass | pass | pass |
session.closeclose replies with session-closed | pass | pass | pass | pass | fail | fail | pass | pass | pass |
session.unknownA request for an unknown session gets unknown-session | pass | pass | fail | fail | fail | fail | fail | pass | pass |
session.closedA closed session is gone | pass | pass | fail | fail | fail | fail | fail | pass | pass |
| eval | |||||||||
eval.valueeval returns the value | pass | pass | pass | pass | pass | pass | pass | pass | pass |
eval.stdoutPrinted output arrives as out before done | pass | pass | pass | pass | pass | pass | pass | pass | pass |
eval.stdout-orderOutput arrives before the value | pass | pass | pass | pass | pass | pass | pass | pass | pass |
eval.stderrError output arrives as err | pass | pass | fail | pass | fail | pass | fail | fail | fail |
eval.error-statusAn eval that throws gets eval-error | pass | pass | fail | pass | pass | pass | fail | pass | pass |
eval.error-reportA failed eval explains itself in err and ex | pass | pass | pass | pass | pass | pass | warn | pass | pass |
eval.survives-errorA session keeps working after an error | pass | pass | pass | pass | pass | pass | pass | pass | pass |
eval.multiple-formsEach form in the code gets its own value | pass | pass | pass | pass | fail | fail | fail | pass | skip |
eval.no-codeAn eval without code gets no-code | pass | pass | warn | warn | warn | warn | warn | pass | pass |
eval.nseval replies say which namespace they ran in | pass | pass | pass | pass | pass | pass | pass | skip | skip |
eval.unknown-nsAn eval in a namespace that doesn't exist gets namespace-not-found | pass | pass | fail | pass | fail | fail | fail | skip | skip |
| stdin | |||||||||
stdin.need-inputCode reading stdin makes the server ask for input | pass | pass | skip | skip | skip | skip | skip | pass | pass |
stdin.roundtripInput sent with stdin reaches the code reading it | pass | pass | skip | skip | skip | skip | skip | pass | pass |
stdin.eofAn empty stdin means end of input | pass | pass | skip | skip | skip | skip | skip | pass | pass |
| interrupt | |||||||||
interrupt.runninginterrupt stops a running eval | pass | pass | skip | skip | skip | skip | skip | pass | pass |
interrupt.no-idAn interrupt without interrupt-id stops what's running | pass | pass | skip | skip | skip | skip | skip | pass | pass |
interrupt.statusAn interrupted eval says it was interrupted | pass | pass | skip | skip | skip | skip | skip | pass | pass |
interrupt.survivesA session keeps working after an interrupt | pass | pass | skip | skip | skip | skip | skip | pass | pass |
interrupt.queuedAn eval waiting for an interrupted one still runs | fail | fail | skip | skip | skip | skip | skip | pass | pass |
interrupt.other-connectionAn interrupted eval ends on its own connection | fail | fail | skip | skip | skip | skip | skip | pass | pass |
interrupt.idleInterrupting an idle session gets session-idle | pass | pass | skip | skip | skip | skip | skip | pass | pass |
interrupt.id-mismatchAn interrupt for another eval gets interrupt-id-mismatch | pass | pass | skip | skip | skip | skip | skip | pass | pass |
| load-file | |||||||||
load-file.valueload-file returns the value of the last form | pass | pass | pass | pass | pass | pass | pass | pass | pass |
load-file.errorA load-file that throws says so in err, ex and eval-error | pass | pass | fail | pass | pass | pass | fail | pass | pass |
| completion | |||||||||
completion.completionscompletions offers what the code could be | pass | skip | skip | skip | skip | pass | skip | pass | pass |
completion.completecomplete offers what the code could be, given a prefix | skip | pass | pass | pass | pass | skip | pass | skip | skip |
completion.complete-symbolcomplete offers what the code could be, given a symbol | skip | pass | pass | pass | pass | skip | pass | skip | skip |
| lookup | |||||||||
lookup.lookuplookup says what a symbol is | pass | skip | skip | skip | skip | pass | skip | pass | pass |
lookup.lookup-unknownlookup finds nothing for a symbol that doesn't exist | pass | skip | skip | skip | skip | pass | skip | pass | pass |
lookup.infoinfo says what a symbol is | skip | pass | fail | fail | fail | skip | pass | skip | skip |
lookup.info-unknowninfo says no-info for a symbol that doesn't exist | skip | pass | fail | fail | fail | skip | pass | skip | skip |
lookup.eldoceldoc gives the arglists of a function | skip | pass | pass | pass | pass | skip | skip | skip | skip |
| bb-repl | |||||||||
bb-repl.connectbb repl --connect can connect | pass | pass | pass | pass | pass | pass | pass | pass | pass |
| calva | |||||||||
calva.connectCalva can connect | pass | pass | pass | pass | pass | pass | pass | pass | pass |
calva.evalCalva can evaluate code from a source file | pass | pass | pass | pass | pass | pass | pass | skip | skip |
calva.load-fileCalva can load a file | pass | pass | pass | pass | pass | pass | pass | pass | pass |
| cider | |||||||||
cider.connectCIDER can connect | pass | pass | pass | pass | pass | pass | pass | pass | pass |
cider.evalCIDER can evaluate code from a source buffer | pass | pass | pass | pass | pass | pass | pass | skip | skip |
cider.replCIDER's REPL can evaluate code | pass | pass | pass | pass | pass | pass | pass | pass | pass |
cider.load-fileCIDER can load a buffer | pass | pass | pass | pass | pass | pass | pass | pass | pass |
| clojure-cli | |||||||||
clojure-cli.evalclojure-cli.repl can evaluate code | pass | pass | pass | pass | pass | pass | pass | skip | skip |
| conjure | |||||||||
conjure.connectConjure can connect | pass | pass | pass | pass | pass | pass | pass | pass | pass |
conjure.evalConjure can evaluate code from a source buffer | pass | pass | pass | pass | pass | pass | pass | skip | skip |
conjure.load-fileConjure can evaluate a file | pass | pass | pass | pass | pass | pass | pass | pass | pass |
| fireplace | |||||||||
fireplace.connectvim-fireplace can connect | pass | pass | skip | skip | skip | skip | skip | skip | skip |
fireplace.evalvim-fireplace can evaluate code | pass | pass | skip | skip | skip | skip | skip | skip | skip |
| neorepl | |||||||||
neorepl.connectneorepl can start its REPL | pass | pass | pass | pass | pass | pass | pass | pass | pass |
neorepl.evalneorepl can evaluate code | pass | pass | pass | pass | pass | pass | pass | pass | pass |
| reply | |||||||||
reply.connectREPLy can start | pass | pass | pass | pass | pass | pass | pass | pass | pass |
| robust | |||||||||
robust.wrong-typesA session keeps working after a request with fields of the wrong type | fail | fail | pass | pass | pass | fail | pass | pass | pass |
robust.sessions-at-onceAn eval in one session doesn't hold up the others | pass | pass | skip | skip | skip | skip | skip | pass | pass |
robust.disconnectA session keeps working after its client went away in the middle of an eval | fail | pass | skip | skip | skip | skip | skip | pass | pass |
robust.bad-framesFrames that aren't requests don't take the server down | pass | pass | fail | pass | pass | pass | pass | pass | pass |
| wire | |||||||||
wire.bencodeEvery frame is valid bencode | pass | pass | pass | pass | pass | pass | pass | pass | pass |
wire.dictEvery message is a dict | pass | pass | pass | pass | pass | pass | pass | pass | pass |
wire.canonicalFrames use canonical bencode | pass | pass | pass | pass | warn | warn | pass | pass | pass |
wire.utf8Strings are valid UTF-8 | pass | pass | pass | pass | pass | pass | pass | pass | pass |
wire.status-typestatus is a list of strings | pass | pass | pass | pass | pass | pass | pass | pass | pass |
wire.field-typesStandard fields are strings | pass | pass | fail | fail | pass | pass | pass | pass | pass |
wire.one-payloadA message carries at most one of value, out and err | pass | pass | pass | pass | pass | pass | pass | pass | pass |
wire.idReplies carry the id of their request | warn | warn | pass | pass | pass | pass | pass | pass | pass |
wire.session-echoReplies to a request with a session carry that session | pass | pass | pass | pass | pass | pass | pass | pass | pass |
wire.one-doneEach request gets exactly one done | pass | pass | pass | pass | pass | pass | pass | pass | pass |
wire.after-doneOnly output follows done | warn | warn | pass | pass | pass | pass | pass | pass | pass |
wire.error-terminalNo output, value or need-input follows an error status | pass | pass | pass | pass | pass | pass | pass | pass | pass |
wire.need-input-aloneneed-input is sent on its own | pass | pass | pass | pass | pass | pass | pass | pass | pass |
| Passed | 69/75 | 72/77 | 49/62 | 53/62 | 49/62 | 48/60 | 49/61 | 66/67 | 65/66 |