Language-neutral FORMAT / TEST / REPL_EVAL / REPL-LIFECYCLE dispatch.
Language extensions register handlers under :ext/language-tools; this
foundation surface exposes stable bare tool names and dispatches to the
active handler for the requested/current language. REPL lifecycle is resource
backed: repl_start creates a language-owned session resource, repl_status
reports it and repl_stop ends one. Live REPLs also surface in the ctx
resources block.
Language-neutral FORMAT / TEST / REPL_EVAL / REPL-LIFECYCLE dispatch. Language extensions register handlers under `:ext/language-tools`; this foundation surface exposes stable bare tool names and dispatches to the active handler for the requested/current language. REPL lifecycle is resource backed: `repl_start` creates a language-owned session resource, `repl_status` reports it and `repl_stop` ends one. Live REPLs also surface in the ctx `resources` block.
(capability-data env)STRUCTURED capability map for the ACTIVE language packs:
{"clojure" ["format" "test" "repl_eval" "repl_start"], "python" [...]}
— nil when none active. Recomputed every turn from active-extensions, so it
GAINS a language the moment its pack activates (e.g. a .py file appears).
INTERNAL: it feeds the EXTENSIONS prompt block and the resources ctx
projection. It is NOT shipped in the model's session dict — that was a
verbatim duplicate of the prompt block's LANGUAGE TOOLS lines.
STRUCTURED capability map for the ACTIVE language packs:
`{"clojure" ["format" "test" "repl_eval" "repl_start"], "python" [...]}`
— nil when none active. Recomputed every turn from active-extensions, so it
GAINS a language the moment its pack activates (e.g. a .py file appears).
INTERNAL: it feeds the EXTENSIONS prompt block and the `resources` ctx
projection. It is NOT shipped in the model's `session` dict — that was a
verbatim duplicate of the prompt block's LANGUAGE TOOLS lines.(capability-matrix env)AUTO capability matrix for the system prompt — the active packs' facade verbs
AUTO capability matrix for the system prompt — the active packs' facade verbs
+ a CERTAIN statement of when each is the tool. nil when no pack is active.
LANGUAGE TOOLS (active packs; language first):
clojure : format_code · run_tests · repl_eval · repl_start
python : repl_eval · repl_start(connect-repl env & args)Attach to an external running REPL: repl_connect(language,{port|build,host?,cwd?}).
CLOJURE only — Vis owns the python and bun runtimes and those packs refuse to attach.
port is REQUIRED unless build names a shadow-cljs build; that attaches to the
project's shadow-cljs watch and selects it, making eval ClojureScript. host defaults
to localhost, and cwd chooses the project directory. Registers the attachment for
eval, tests, and context but never owns or kills its process; stop only detaches.
Attach to an external running REPL: `repl_connect(language,{port|build,host?,cwd?})`.
CLOJURE only — Vis owns the python and bun runtimes and those packs refuse to attach.
`port` is REQUIRED unless `build` names a shadow-cljs build; that attaches to the
project's `shadow-cljs watch` and selects it, making eval ClojureScript. `host` defaults
to localhost, and `cwd` chooses the project directory. Registers the attachment for
eval, tests, and context but never owns or kills its process; stop only detaches.(format-code env & args)Format through a pack: format_code(language,arg); omit language only for paths-based inference. Source/{"code":...} returns changed + char-delta, never text. {"paths":[...]} (always a list) recursively formats files/dirs in place and returns per-file changes, never text. Nonblank code and nonblank path/paths targets are mutually exclusive; conflicting selectors are rejected before any files change. Blank target selectors are ignored for explicit snippets. Omit code/paths for default source paths recursively. python also takes ruff's own line_length and config.
Format through a pack: `format_code(language,arg)`; omit `language` only for paths-based inference. Source/`{"code":...}` returns changed + char-delta, never text. `{"paths":[...]}` (always a list) recursively formats files/dirs in place and returns per-file changes, never text. Nonblank `code` and nonblank `path`/`paths` targets are mutually exclusive; conflicting selectors are rejected before any files change. Blank target selectors are ignored for explicit snippets. Omit code/paths for default source paths recursively. python also takes ruff's own `line_length` and `config`.
(lint-code env & args)Lint through a pack: lint_code(language,arg); omit language only for file/workspace inference. Source/{"code":...} lints a snippet; {"paths":[...]} (always a list) lints disk. Omit code/paths for defaults. Returns findings and severity counts. python also takes ruff's own select, ignore, line_length and config for this call.
Lint through a pack: `lint_code(language,arg)`; omit `language` only for file/workspace inference. Source/`{"code":...}` lints a snippet; `{"paths":[...]}` (always a list) lints disk. Omit code/paths for defaults. Returns findings and severity counts. python also takes ruff's own `select`, `ignore`, `line_length` and `config` for this call.
(prompt env)The language-facade reference: the AUTO capability matrix (active packs only)
language is explicit only when several packs match.The language-facade reference: the AUTO capability matrix (active packs only) + the bare facade verbs. nil when no language pack is active, so a non-coding or single-language workspace carries nothing extra. Each verb's own docstring holds its args/return; `language` is explicit only when several packs match.
(repl-eval env & args)Eval in an already-running project REPL: repl_eval(language,{code,cwd,id,timeout_ms}).
code is the one REQUIRED key; language may lead the call. Nothing else is required:
cwd chooses the project directory (default the workspace root), id/repl_id picks
one of several REPLs, and timeout_ms is this eval's budget. Clojure also reads ns
(the namespace the form is read in) and port/host, which dial an nREPL directly
instead of a REPL this session owns.
Eval in an already-running project REPL: `repl_eval(language,{code,cwd,id,timeout_ms})`.
`code` is the one REQUIRED key; `language` may lead the call. Nothing else is required:
`cwd` chooses the project directory (default the workspace root), `id`/`repl_id` picks
one of several REPLs, and `timeout_ms` is this eval's budget. Clojure also reads `ns`
(the namespace the form is read in) and `port`/`host`, which dial an nREPL directly
instead of a REPL this session owns.(repl-start env & args)Start a language REPL resource: repl_start(language,{cwd,id,aliases,env}).
NOTHING is required: language is inferred, while cwd chooses the project directory
and defaults to the WORKSPACE ROOT. id LABELS a second REPL in one project (python/bun;
a clojure id is derived from its cwd), aliases is clojure-only, and env belongs to
THIS REPL. Neither port nor build starts anything here — attaching to a process
already running is repl_connect. There is no restart: repl_stop, then repl_start.
Start a language REPL resource: `repl_start(language,{cwd,id,aliases,env})`.
NOTHING is required: `language` is inferred, while `cwd` chooses the project directory
and defaults to the WORKSPACE ROOT. `id` LABELS a second REPL in one project (python/bun;
a clojure id is derived from its `cwd`), `aliases` is clojure-only, and `env` belongs to
THIS REPL. Neither `port` nor `build` starts anything here — attaching to a process
already running is `repl_connect`. There is no restart: `repl_stop`, then `repl_start`.(repl-status env & args)Report REPL state: repl_status(language,{cwd}) — the pack's answer for that
project PLUS resources, every live REPL of this session whatever directory it
runs in. Nothing is required; the project directory defaults to the workspace root.
A REPL id answers for that one REPL alone.
Report REPL state: `repl_status(language,{cwd})` — the pack's answer for that
project PLUS `resources`, every live REPL of this session whatever directory it
runs in. Nothing is required; the project directory defaults to the workspace root.
A REPL id answers for that one REPL alone.(repl-stop env & args)Stop a REPL: repl_stop(id) with the exact id repl_start/repl_status
answered with. NOTHING is required: language is inferred and the project directory
defaults to the WORKSPACE ROOT, so a bare repl_stop() ends the inferred pack's REPL
there, which is rarely the one you meant. build (clojure) detaches just that
shadow-cljs attachment.
Stop a REPL: `repl_stop(id)` with the exact id `repl_start`/`repl_status` answered with. NOTHING is required: `language` is inferred and the project directory defaults to the WORKSPACE ROOT, so a bare `repl_stop()` ends the inferred pack's REPL there, which is rarely the one you meant. `build` (clojure) detaches just that shadow-cljs attachment.
(run-tests env & args)Run through a pack: run_tests(language,arg). NOTHING is required: omit arg to
run every test, and language is inferred from the paths and the workspace. arg
is a path string or a map: paths (files, directories, or <path>::<test-name>
node ids — the selector every language shares; ::<test-name> alone finds that
test wherever it lives) selects; clojure ALSO takes ns / nses (a namespace
name, or ns/var for one test) and resolves it the same way. JS tests run
through the project's shadow-cljs build; build selects one explicitly and
chooses JS for .cljc tests too. include / exclude narrow by metadata tag; cwd chooses
the project directory and defaults to the WORKSPACE ROOT, which is where a relative
paths entry resolves; runner picks the python backend
("project" for the project interpreter's own pytest, else the hermetic sandbox).
aliases (clojure) adds deps.edn classpath aliases or selects an executable
runner; a declared :test is kept but never invented. Lazytest/Kaocha focus
follows the runner's entry point, including Kaocha -X. Unsupported focus and
ambiguous shadow builds fail before launch. The JS adapter supports namespace,
not var/tag focus; classpath belongs to shadow-cljs.edn's :deps/:lein. Node tests
compile without autorun, then execute separately. External shadow config and
dynamic output/selection settings are refused rather than guessed. A reused
JVM REPL cannot apply aliases and says so. List selectors stay lists, even one.
Run through a pack: `run_tests(language,arg)`. NOTHING is required: omit `arg` to run every test, and `language` is inferred from the paths and the workspace. `arg` is a path string or a map: `paths` (files, directories, or `<path>::<test-name>` node ids — the selector every language shares; `::<test-name>` alone finds that test wherever it lives) selects; clojure ALSO takes `ns` / `nses` (a namespace name, or `ns/var` for one test) and resolves it the same way. JS tests run through the project's shadow-cljs build; `build` selects one explicitly and chooses JS for .cljc tests too. `include` / `exclude` narrow by metadata tag; `cwd` chooses the project directory and defaults to the WORKSPACE ROOT, which is where a relative `paths` entry resolves; `runner` picks the python backend (`"project"` for the project interpreter's own pytest, else the hermetic sandbox). `aliases` (clojure) adds deps.edn classpath aliases or selects an executable runner; a declared :test is kept but never invented. Lazytest/Kaocha focus follows the runner's entry point, including Kaocha -X. Unsupported focus and ambiguous shadow builds fail before launch. The JS adapter supports namespace, not var/tag focus; classpath belongs to shadow-cljs.edn's :deps/:lein. Node tests compile without autorun, then execute separately. External shadow config and dynamic output/selection settings are refused rather than guessed. A reused JVM REPL cannot apply aliases and says so. List selectors stay lists, even one.
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 |