Thin, observable nREPL client for clj/eval.
Connection model:
nrepl.core/connect socket per [host port] key, cached
on a defonce atom so we survive (require :reload) during
development.eval! we open a fresh client-session against the
cached connection. Sessions are not shared across calls so a
caller's *1/*e/dynamic var binding never leaks across
Vis tool invocations.IOException / nil
message stream) and the entry is evicted; the next call
re-dials.Returned shape (success) — STRING keys (crosses the strings-only boundary
as a tool :result; enrichment adds "error_message"/"error_data"/"trace"):
{"value" "42" ; pr-str of the LAST form's value, or nil
"values" ["1" "42"] ; pr-str of every emitted value
"out" "hello\n" ; stdout aggregated
"err" "" ; stderr aggregated
"ns" "user" ; final ns name
"status" #{"done"} ; nREPL status set (strings)
"ex" nil ; exception class name, when status :ex
"root_ex" nil ; root exception class name
"ms" 12 ; wall-clock duration
"port" 7888
"timed_out" false}
Failure paths throw ex-info with :type :clj/nrepl-* so the
Vis tool wrapper can surface a clean error to the model.
Thin, observable nREPL client for `clj/eval`.
Connection model:
* One `nrepl.core/connect` socket per `[host port]` key, cached
on a `defonce` atom so we survive `(require :reload)` during
development.
* On every `eval!` we open a fresh `client-session` against the
cached connection. Sessions are *not* shared across calls so a
caller's `*1`/`*e`/dynamic var binding never leaks across
Vis tool invocations.
* Stale / closed sockets are detected (`IOException` / `nil`
message stream) and the entry is evicted; the next call
re-dials.
Returned shape (success) — STRING keys (crosses the strings-only boundary
as a tool `:result`; enrichment adds "error_message"/"error_data"/"trace"):
{"value" "42" ; pr-str of the LAST form's value, or nil
"values" ["1" "42"] ; pr-str of every emitted value
"out" "hello\n" ; stdout aggregated
"err" "" ; stderr aggregated
"ns" "user" ; final *ns* name
"status" #{"done"} ; nREPL status set (strings)
"ex" nil ; exception class name, when status :ex
"root_ex" nil ; root exception class name
"ms" 12 ; wall-clock duration
"port" 7888
"timed_out" false}
Failure paths throw `ex-info` with `:type :clj/nrepl-*` so the
Vis tool wrapper can surface a clean error to the model.(close-all!)Close every cached connection. Idempotent. Useful from tests / doctor / shutdown hooks.
Close every cached connection. Idempotent. Useful from tests / doctor / shutdown hooks.
(eval! {:keys [host port code ns timeout-ms pretty? print-margin]
:or {host "localhost" timeout-ms 30000 print-margin 100}})Evaluate code in the nREPL at host:port. Opts:
:host defaults to "localhost"
:ns starting namespace, e.g. "user"
:timeout-ms default 30000
:pretty? when true, ask nREPL's print middleware to pretty-print the
value(s) SERVER-SIDE via nrepl.util.print/pprint — so the
live object is formatted where it lives (handles unreadable
objects / lazy seqs) and :value/:values come back as
multi-line, indented text. Output stays valid EDN.
:print-margin right-margin columns for pretty printing (default 100)
Always returns a map (see ns docstring). Connection failures
throw :clj/nrepl-connect-failed; everything else (eval error,
timeout) is reported inside the returned map so the model can
read it as data.
Evaluate `code` in the nREPL at `host:port`. Opts:
:host defaults to "localhost"
:ns starting namespace, e.g. "user"
:timeout-ms default 30000
:pretty? when true, ask nREPL's print middleware to pretty-print the
value(s) SERVER-SIDE via `nrepl.util.print/pprint` — so the
live object is formatted where it lives (handles unreadable
objects / lazy seqs) and `:value`/`:values` come back as
multi-line, indented text. Output stays valid EDN.
:print-margin right-margin columns for pretty printing (default 100)
Always returns a map (see ns docstring). Connection failures
throw `:clj/nrepl-connect-failed`; everything else (eval error,
timeout) is reported inside the returned map so the model can
read it as data.(probe! {:keys [host port timeout-ms] :or {host "localhost" timeout-ms 100}})Best-effort liveness probe for the nREPL at host:port. Sends a single
describe op (no code execution) under a SHORT timeout and classifies:
{:status :up :versions {:clojure ..} :dialect :clj|:cljs :cwd "/path"}
— connected and the server answered describe.
{:status :unresponsive}
— socket opened but no clean describe reply in budget.
{:status :down} — could not connect (stale .nrepl-port, dead proc).
:dialect (clj vs cljs) is read from the describe metadata; :cwd is the
server JVM's working directory via one tiny eval (nil when unavailable).
Both are best-effort and only present when :up.
Never throws. Reuses the cached connection (warming the same pool
eval! uses). The short :timeout-ms (default 100) is passed to
nrepl/client, which bounds each response read regardless of the
cached connection's transport timeout.
Best-effort liveness probe for the nREPL at `host:port`. Sends a single
`describe` op (no code execution) under a SHORT timeout and classifies:
{:status :up :versions {:clojure ..} :dialect :clj|:cljs :cwd "/path"}
— connected and the server answered describe.
{:status :unresponsive}
— socket opened but no clean describe reply in budget.
{:status :down} — could not connect (stale `.nrepl-port`, dead proc).
`:dialect` (clj vs cljs) is read from the describe metadata; `:cwd` is the
server JVM's working directory via one tiny eval (nil when unavailable).
Both are best-effort and only present when `:up`.
Never throws. Reuses the cached connection (warming the same pool
`eval!` uses). The short `:timeout-ms` (default 100) is passed to
`nrepl/client`, which bounds each response read regardless of the
cached connection's transport timeout.cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |