Project-local Python extensions — trusted-context plug-ins.
Vis extensions are normally Clojure libraries baked into the binary at
build time. This namespace adds a second, fully dynamic authoring path:
drop a *.py file into
~/.vis/extensions/ (global — every project) <project>/.vis/extensions/ (project-local — this project only)
and it loads at startup (and on /reload) in BOTH the JVM and the
native image — the extension is Python all the way down, so nothing here
defines a class at runtime.
Each file is first evaluated in a TRUSTED gateway-wide registration namespace. When one of its callables runs for a gateway session, the extension is realized again in the session's separate trusted worker. The sandbox has its own process, interpreter and host-call connection. Extension imports and native-library state are shared only with other trusted extensions in that session. Another session owns another pair of processes.
The model can call an extension TOOL through the ordinary host wrapper, envelope-
checked like any tool, but cannot choose the trusted identity or evaluate code in
the extension namespace. The blockether.vis.extension API exposes host capabilities;
only sealed data crosses the boundary, never live Python or host objects.
Startup, reload and calls with no owning session use the shared registration worker.
A context is only a NAMESPACE in its owning embedded interpreter: opening one costs
a dict, and closing one drops the extension's Python with it. Calls into an extension
(tool, activation, prompt, slash, op hook) are serialized with locking on its
session name, the same proven pattern as the printer context.
The file's top-level vis.register_extension(vis.Extension(...)) call registers through the
ordinary register-extension! — from the registry's perspective a
Python extension is indistinguishable from a Clojure one (activation,
prompt assembly, slash dispatch, vis-agent extension list all just work).
A file that fails to load becomes a load-failure warning (surfaced via
vis-agent doctor), never a crash.
Project-local Python extensions — trusted-context plug-ins. Vis extensions are normally Clojure libraries baked into the binary at build time. This namespace adds a second, fully dynamic authoring path: drop a `*.py` file into ~/.vis/extensions/ (global — every project) <project>/.vis/extensions/ (project-local — this project only) and it loads at startup (and on `/reload`) in BOTH the JVM and the native image — the extension is Python all the way down, so nothing here defines a class at runtime. Each file is first evaluated in a TRUSTED gateway-wide registration namespace. When one of its callables runs for a gateway session, the extension is realized again in the session's separate trusted worker. The sandbox has its own process, interpreter and host-call connection. Extension imports and native-library state are shared only with other trusted extensions in that session. Another session owns another pair of processes. The model can call an extension TOOL through the ordinary host wrapper, envelope- checked like any tool, but cannot choose the trusted identity or evaluate code in the extension namespace. The `blockether.vis.extension` API exposes host capabilities; only sealed data crosses the boundary, never live Python or host objects. Startup, reload and calls with no owning session use the shared registration worker. A context is only a NAMESPACE in its owning embedded interpreter: opening one costs a dict, and closing one drops the extension's Python with it. Calls into an extension (tool, activation, prompt, slash, op hook) are serialized with `locking` on its session name, the same proven pattern as the printer context. The file's top-level `vis.register_extension(vis.Extension(...))` call registers through the ordinary `register-extension!` — from the registry's perspective a Python extension is indistinguishable from a Clojure one (activation, prompt assembly, slash dispatch, `vis-agent extension list` all just work). A file that fails to load becomes a load-failure warning (surfaced via `vis-agent doctor`), never a crash.
(add-change-listener! listener-id f)Subscribe f to Python-extension set changes. f receives
{:project-root root :extensions [<validated ext map> ...] :removed [<ext-name> ...]}
after every (re)load that changed anything. :project-root is nil for the global
catalog; :extensions is that scope's full freshly-registered set and :removed
the names that no longer exist in it. Re-registering the same listener-id
replaces the old listener. Returns listener-id.
Subscribe `f` to Python-extension set changes. `f` receives
`{:project-root root :extensions [<validated ext map> ...] :removed [<ext-name> ...]}`
after every (re)load that changed anything. `:project-root` is nil for the global
catalog; `:extensions` is that scope's full freshly-registered set and `:removed`
the names that no longer exist in it. Re-registering the same `listener-id`
replaces the old listener. Returns `listener-id`.(ensure-python-extensions-loaded!)(ensure-python-extensions-loaded! opts)Admit each project's configuration and extension bytes once. Session cache misses
and recycling reuse that project's admitted catalog; only explicit reload adopts edits.
:global-only? admits the global catalog alone, for a process with no project bound.
Admit each project's configuration and extension bytes once. Session cache misses and recycling reuse that project's admitted catalog; only explicit reload adopts edits. `:global-only?` admits the global catalog alone, for a process with no project bound.
(install-package! source
{:keys [trust subdirectory revision version directory save
project]})Install a source; with save, persist its declaration and transfer management to sync. Preflight config before admission. Roll back the admitted source if saving fails.
Install a source; with save, persist its declaration and transfer management to sync. Preflight config before admission. Roll back the admitted source if saving fails.
(install-test-slash! f)Install the /test slash handler. It lives in python.test-runner, which
requires this namespace for its trusted-context builder, so the process
wiring installs it.
Install the `/test` slash handler. It lives in `python.test-runner`, which requires this namespace for its trusted-context builder, so the process wiring installs it.
(load-failures)(load-failures root)Load failures visible in a project, including global extensions; the current
project by default, and global extensions alone for a nil root.
Each row names the file, error, retained extension, stale? status,
loaded/requested source fingerprints and readiness changes.
Load failures visible in a project, including global extensions; the current project by default, and global extensions alone for a nil `root`. Each row names the file, error, retained extension, stale? status, loaded/requested source fingerprints and readiness changes.
(load-python-extensions!)(load-python-extensions! opts)Load global extensions and the bound project's independent catalog. Declared
packages and missing environments are prepared before registration. Explicit
:dirs loads an unmanaged catalog; :project-root scopes that catalog.
Load global extensions and the bound project's independent catalog. Declared packages and missing environments are prepared before registration. Explicit `:dirs` loads an unmanaged catalog; `:project-root` scopes that catalog.
(loaded-python-extensions)(loaded-python-extensions root)Snapshot of the effective Python extensions in a project, the current one by
default: {<canonical-path> {:sha ... :ext-name ...}} (context handle elided).
Project declarations override global extensions with the same name. A nil
root lists global extensions alone.
Snapshot of the effective Python extensions in a project, the current one by
default: `{<canonical-path> {:sha ... :ext-name ...}}` (context handle elided).
Project declarations override global extensions with the same name. A nil
`root` lists global extensions alone.(net-probe-report method target headers-json body)Guard-only egress probe for the in-sandbox network_probe(...) tool. Parses
target (an http(s) URL or a bare host[:port]), then runs the gateway's
Tier-1 host/port/SSRF gate + EVERY registered network filter over a SYNTHETIC
ctx via [[egress/probe]] — PURE: no socket, no egress, nothing is sent. Returns
a JSON string {scheme, ctx, tier1, filters} (or {error}) — the strings-only
boundary the sandbox glue json.loadses before merging its own local
network_filters and printing the verdict. method may be blank/nil.
headers-json is a JSON object string of request headers (or blank) and body
is the request body string (or blank); both are merged into the synthetic
HTTP-phase ctx so :headers/:body filter rules can be simulated.
Guard-only egress probe for the in-sandbox `network_probe(...)` tool. Parses
`target` (an http(s) URL or a bare `host[:port]`), then runs the gateway's
Tier-1 host/port/SSRF gate + EVERY registered network filter over a SYNTHETIC
ctx via [[egress/probe]] — PURE: no socket, no egress, nothing is sent. Returns
a JSON string `{scheme, ctx, tier1, filters}` (or `{error}`) — the strings-only
boundary the sandbox glue `json.loads`es before merging its own local
`network_filter`s and printing the verdict. `method` may be blank/nil.
`headers-json` is a JSON object string of request headers (or blank) and `body`
is the request body string (or blank); both are merged into the synthetic
HTTP-phase ctx so `:headers`/`:body` filter rules can be simulated.(package-versions source {:keys [subdirectory directory]})List approved releases and update availability for a GitHub repository slug or URL.
List approved releases and update availability for a GitHub repository slug or URL.
(prepare-project! root)Prepare a project's declared packages, dependencies and isolated extension catalog. Adding or opening a project admits its configured code; reload adopts later edits.
Prepare a project's declared packages, dependencies and isolated extension catalog. Adding or opening a project admits its configured code; reload adopts later edits.
(reload-python-extensions!)(reload-python-extensions! opts)Reload global extensions and the calling project, preserving other project catalogs.
Reload global extensions and the calling project, preserving other project catalogs.
(remove-change-listener! listener-id)Remove a listener registered with add-change-listener!. Returns nil.
Remove a listener registered with [[add-change-listener!]]. Returns nil.
(rollback-package! source {:keys [trust subdirectory version directory]})Restore a previous pinned source or an explicitly selected older approved release.
Restore a previous pinned source or an explicitly selected older approved release.
(sync-packages! {:keys [trust refresh prune dry-run project global]})Explicitly reconcile YAML package scopes and prepare their uv environments.
Never imports package entrypoints or reloads a live gateway. Dry-run is inert.
A prepared result names its environment's site_packages for the loader to reuse.
Explicitly reconcile YAML package scopes and prepare their uv environments. Never imports package entrypoints or reloads a live gateway. Dry-run is inert. A prepared result names its environment's `site_packages` for the loader to reuse.
(update-package! source {:keys [trust subdirectory version directory]})Explicitly activate a newer approved source snapshot; dependencies prepare on reload.
Explicitly activate a newer approved source snapshot; dependencies prepare on reload.
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 |