Worker-side clj analyzer execution. Mirrors the env-construction and
analyze-form body that live in skeptic.analysis.annotate, with no
Skeptic / Schema / Malli dependency. The worker reads the project's own
source files with the real Clojure reader and analyzes them in bulk; no
form ever crosses host->worker (the host sends only a source-file path).
tools.analyzer.* and tools.reader.* are required eagerly at ns-load
(worker boot), under the JVM launch classloader. The launch-classpath
order already prefers project entries (worker-classpath-entries in
classpath.clj), so the project's pinned tools.analyzer version wins
via first-occurrence; no lazy require is needed.
Worker-side clj analyzer execution. Mirrors the env-construction and `analyze-form` body that live in `skeptic.analysis.annotate`, with no Skeptic / Schema / Malli dependency. The worker reads the project's own source files with the real Clojure reader and analyzes them in bulk; no form ever crosses host->worker (the host sends only a source-file path). tools.analyzer.* and tools.reader.* are required eagerly at ns-load (worker boot), under the JVM launch classloader. The launch-classpath order already prefers project entries (`worker-classpath-entries` in `classpath.clj`), so the project's pinned tools.analyzer version wins via first-occurrence; no lazy require is needed.
Worker-side cljs analyzer execution. Mirrors the parse + reader-loop
that live in skeptic.cljs.analyzer-driver, with no Skeptic / Schema /
Malli dependency. The host-side source-file wrapper is rewired to issue a
worker RPC instead of running the cljs analyzer locally.
Wire payloads carry the source-file descriptor only; the cljs compiler state never crosses the wire.
cljs.analyzer / cljs.analyzer.api / cljs.env / cljs.compiler are loaded
lazily inside with-analysis-bindings so they intern from the project's
pinned clojurescript version when present, not Skeptic's runtime-cp version
at worker boot.
Worker-side cljs analyzer execution. Mirrors the parse + reader-loop that live in `skeptic.cljs.analyzer-driver`, with no Skeptic / Schema / Malli dependency. The host-side source-file wrapper is rewired to issue a worker RPC instead of running the cljs analyzer locally. Wire payloads carry the source-file descriptor only; the cljs compiler state never crosses the wire. cljs.analyzer / cljs.analyzer.api / cljs.env / cljs.compiler are loaded lazily inside `with-analysis-bindings` so they intern from the project's pinned clojurescript version when present, not Skeptic's runtime-cp version at worker boot.
Worker launch classpath assembly. Skeptic owns its worker runtime as a
coordinate declaration in skeptic.worker.deps/worker-deps; the lein and
deps.edn callers each resolve those coordinates through their own build
system and hand the resolved jar list (worker-jars) plus the project
classpath (project-classpath-entries) to worker-classpath-entries.
The result is a single launch classpath string: project-cp first, worker
jars second, Skeptic's own skeptic.worker.* source entry tail (so the
worker JVM can require its own server namespace at boot).
Worker launch classpath assembly. Skeptic owns its worker runtime as a coordinate declaration in `skeptic.worker.deps/worker-deps`; the lein and deps.edn callers each resolve those coordinates through their own build system and hand the resolved jar list (`worker-jars`) plus the project classpath (`project-classpath-entries`) to `worker-classpath-entries`. The result is a single launch classpath string: project-cp first, worker jars second, Skeptic's own `skeptic.worker.*` source entry tail (so the worker JVM can require its own server namespace at boot).
Host-side nREPL client: connect to a worker port, send ops, return replies.
Uses the Transport protocol directly (send + recv) for synchronous
request-response semantics. Does NOT use nrepl.core/client or
nrepl.core/message — those layer lazy seqs and timeouts designed for
interactive REPLs, not RPC.
nrepl.* namespaces are NOT required at namespace-load time. The worker
loads this namespace via server.clj's :require to get loopback-conn and
the loopback branch of ask — neither of which touches nrepl. Host-facing
functions below defer their nrepl loads via requiring-resolve, so the
project's pinned nrepl wins via the launch classpath's project-first
ordering.
Host-side nREPL client: connect to a worker port, send ops, return replies. Uses the Transport protocol directly (`send` + `recv`) for synchronous request-response semantics. Does NOT use nrepl.core/client or nrepl.core/message — those layer lazy seqs and timeouts designed for interactive REPLs, not RPC. nrepl.* namespaces are NOT required at namespace-load time. The worker loads this namespace via server.clj's :require to get `loopback-conn` and the loopback branch of `ask` — neither of which touches nrepl. Host-facing functions below defer their nrepl loads via `requiring-resolve`, so the project's pinned nrepl wins via the launch classpath's project-first ordering.
Single source of truth for Skeptic's worker runtime coordinates.
Both runtime entrypoints consume this declaration:
leiningen.skeptic resolves it via leiningen's aether wrapper.skeptic.cli.main resolves it via tools.deps.The 10 coordinates are the namespaces F1's walk identified as load-bearing for the worker JVM: clojure, clojurescript, tools.analyzer(.jvm), tools.reader, core.cache/memoize, data.priority-map, transit-clj, nrepl. Whatever each build system transitively resolves from this set is the worker's runtime universe under that build system.
skeptic/project.clj's :worker profile and skeptic/deps.edn's
:worker alias mirror this vector for ad-hoc invocations like
lein with-profile +worker classpath and clj -A:worker; the runtime
code paths read FROM this var, not from those build-file declarations.
Single source of truth for Skeptic's worker runtime coordinates. Both runtime entrypoints consume this declaration: - `leiningen.skeptic` resolves it via leiningen's aether wrapper. - `skeptic.cli.main` resolves it via tools.deps. The 10 coordinates are the namespaces F1's walk identified as load-bearing for the worker JVM: clojure, clojurescript, tools.analyzer(.jvm), tools.reader, core.cache/memoize, data.priority-map, transit-clj, nrepl. Whatever each build system transitively resolves from this set is the worker's runtime universe under that build system. `skeptic/project.clj`'s `:worker` profile and `skeptic/deps.edn`'s `:worker` alias mirror this vector for ad-hoc invocations like `lein with-profile +worker classpath` and `clj -A:worker`; the runtime code paths read FROM this var, not from those build-file declarations.
Host-side worker process lifecycle: spawn a JVM running skeptic.worker.server,
read the port handshake off its stdout, and tear it down. The caller passes
a single launch classpath assembled by skeptic.worker.classpath —
project-cp first, worker jars second, Skeptic's own worker source tail.
Host-side worker process lifecycle: spawn a JVM running skeptic.worker.server, read the port handshake off its stdout, and tear it down. The caller passes a single launch classpath assembled by `skeptic.worker.classpath` — project-cp first, worker jars second, Skeptic's own worker source tail.
Worker-side nREPL server. Runs in the spawned JVM on the combined
project-first launch classpath and answers host requests on demand. Project
operations run on the clojure.main launch thread, so project code loads
exactly as the project's own runtime loads it — Skeptic adds no reader-Var
or loading machinery. Plan 2 Phase 1.5 adds the handle-table machinery: every Class
operand on the wire is an opaque handle (integer for bootstrap-interned
host-runtime classes; UUID-string for project classes). Worker is sole owner
of Class/forName, .isAssignableFrom, instance?, and class equality.
Phase 5 adds the analyzer ops. The analyzer-execution glue lives in
skeptic.worker.analyzer-clj / skeptic.worker.analyzer-cljs. No other
skeptic.* namespace is required from this server: Skeptic's own analysis
code and Plumatic Schema / Malli stay on the host (B3/B4).
nREPL is lazy-loaded inside start! from the worker JVM's single launch
classloader (project-cp first, worker jars second). The ns form does NOT
require any nrepl.* namespace at load time — projects pinning a different
nrepl win their version via first-occurrence on the launch cp. The
wrap-* dispatchers are let-bound inside start!, closing over locally
resolved nrepl.transport/send, nrepl.misc/response-for, and
nrepl.server/{start-server,unknown-op}. Descriptor metadata is dead
code under the explicit handler thread and has been removed.
Worker-side nREPL server. Runs in the spawned JVM on the combined
project-first launch classpath and answers host requests on demand. Project
operations run on the clojure.main launch thread, so project code loads
exactly as the project's own runtime loads it — Skeptic adds no reader-Var
or loading machinery. Plan 2 Phase 1.5 adds the handle-table machinery: every Class
operand on the wire is an opaque handle (integer for bootstrap-interned
host-runtime classes; UUID-string for project classes). Worker is sole owner
of `Class/forName`, `.isAssignableFrom`, `instance?`, and class equality.
Phase 5 adds the analyzer ops. The analyzer-execution glue lives in
`skeptic.worker.analyzer-clj` / `skeptic.worker.analyzer-cljs`. No other
`skeptic.*` namespace is required from this server: Skeptic's own analysis
code and Plumatic Schema / Malli stay on the host (B3/B4).
nREPL is lazy-loaded inside `start!` from the worker JVM's single launch
classloader (project-cp first, worker jars second). The ns form does NOT
require any nrepl.* namespace at load time — projects pinning a different
nrepl win their version via first-occurrence on the launch cp. The
`wrap-*` dispatchers are let-bound inside `start!`, closing over locally
resolved `nrepl.transport/send`, `nrepl.misc/response-for`, and
`nrepl.server/{start-server,unknown-op}`. Descriptor metadata is dead
code under the explicit handler thread and has been removed.Length-prefixed Transit+msgpack transport for Skeptic's private nREPL
worker link. The Transport protocol is implemented in the peer namespace
skeptic.worker.transport-impl, which is required lazily on first
transit call so neither nrepl.transport nor the deftype's Protocol
symbol resolves at this namespace's load time.
Length-prefixed Transit+msgpack transport for Skeptic's private nREPL worker link. The Transport protocol is implemented in the peer namespace `skeptic.worker.transport-impl`, which is required lazily on first `transit` call so neither nrepl.transport nor the deftype's Protocol symbol resolves at this namespace's load time.
Holds the deftype that implements nrepl.transport/Transport over the
Transit+msgpack framing helpers in skeptic.worker.transport. This
namespace is required lazily by skeptic.worker.transport/transit so
nrepl.transport's Transport protocol resolves at the project's pinned
version, not Skeptic's runtime-cp version at worker boot.
Holds the deftype that implements `nrepl.transport/Transport` over the Transit+msgpack framing helpers in `skeptic.worker.transport`. This namespace is required lazily by `skeptic.worker.transport/transit` so nrepl.transport's Transport protocol resolves at the project's pinned version, not Skeptic's runtime-cp version at worker boot.
No vars found in this namespace.
Host-safe wire-contract constants shared by both JVMs. Holds ONLY the keys and accessors for values that cross the worker->host AST boundary; carries no nREPL, tools.analyzer, or other worker-classpath dependency, so the host may require it without re-coupling to worker-only code.
The non-EDN sentinel: a raw analyzer-AST :val/:form/:raw-forms leaf
outside the wire-safe set (plain EDN scalars/colls plus the transit-carried
leaves: char, UUID, exact java.util.Date) is shipped as
{::nonedn true ::class <class-handle>} — regex Patterns, fn objects, Vars,
Namespaces, and any project-runtime object a data reader produced (a joda
DateTime from a tagged literal). The host types it by its class via the
carried handle; it never inspects the original value. The transport's
default-handler backstop ships anything that slips past projection as
{::nonedn true ::class-name <name> ::string <print>} — same host typing,
name resolved to a handle lazily.
Form metadata: the worker captures the host-read meta keys off each form into
a plain data vector in clojure.walk/postwalk order (capture-form-meta);
the host replays them onto the structurally-identical received form in the
same order (apply-form-meta). Shape is never altered, so structural form
walks survive.
Host-safe wire-contract constants shared by both JVMs. Holds ONLY the keys
and accessors for values that cross the worker->host AST boundary; carries no
nREPL, tools.analyzer, or other worker-classpath dependency, so the host may
require it without re-coupling to worker-only code.
The non-EDN sentinel: a raw analyzer-AST `:val`/`:form`/`:raw-forms` leaf
outside the wire-safe set (plain EDN scalars/colls plus the transit-carried
leaves: char, UUID, exact java.util.Date) is shipped as
`{::nonedn true ::class <class-handle>}` — regex Patterns, fn objects, Vars,
Namespaces, and any project-runtime object a data reader produced (a joda
DateTime from a tagged literal). The host types it by its class via the
carried handle; it never inspects the original value. The transport's
default-handler backstop ships anything that slips past projection as
`{::nonedn true ::class-name <name> ::string <print>}` — same host typing,
name resolved to a handle lazily.
Form metadata: the worker captures the host-read meta keys off each form into
a plain data vector in `clojure.walk/postwalk` order (`capture-form-meta`);
the host replays them onto the structurally-identical received form in the
same order (`apply-form-meta`). Shape is never altered, so structural form
walks survive.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 |