Liking cljdoc? Tell your friends :D
Clojure only.

com.blockether.vis.core

vis - broad host facade.

This is the ONLY namespace extensions, channel adapters, embedded callers, and tests should import. It deliberately re-exports host, registry, runtime, persistence, prompt, diagnostic, and sandbox helpers from com.blockether.vis.internal.*. The internal tree is not stable; the names exposed here are the host contract.

Canonical runtime language: Session -> Turn -> Iteration -> Block.

A Turn is one user request plus assistant answer inside a Session. New code and documentation should use turn/user-request language.

Primary surfaces:

  • Session / turn runtime: create!, send!, turn!, by-id, by-channel, env-for, close!, delete!, set-title!.
  • Environment runtime: create-environment, dispose-environment!, get-router, rebuild-router!, resolve-effective-model.
  • Extension contract: extension, symbol, value, render-prompt, register-extension!, registered-extensions, discovery, reload.
  • Registries: command, channel, provider, and backend registration helpers for host-owned and embedded use.
  • Persistence facade: db-* functions and connection helpers. The implementation namespace / extension slot are spelled persistance; human-facing language is Persistence.
  • Prompt / Python-sandbox / formatting / cancellation / notifications / doctor helpers shared by channels and extensions.

Not every export is equally high-level. send!, extension maps, registry builders, read-side persistence helpers, and Markdown export are the preferred integration surface. Low-level sandbox, parse-repair, dispatcher, and write-side db helpers are exported because this is a host facade, but ordinary extensions should avoid depending on them unless they are implementing host-level behavior.

Binary entry: -main (invoked by clojure -M:vis, AOT'd to a Java entry class via :gen-class for the GraalVM native-image build).

vis - broad host facade.

This is the ONLY namespace extensions, channel adapters, embedded
callers, and tests should import. It deliberately re-exports host,
registry, runtime, persistence, prompt, diagnostic, and sandbox
helpers from `com.blockether.vis.internal.*`. The internal tree is
not stable; the names exposed here are the host contract.

Canonical runtime language:
  Session -> Turn -> Iteration -> Block.

A Turn is one user request plus assistant answer inside a Session.
New code and documentation should use turn/user-request language.

Primary surfaces:
  - Session / turn runtime: create!, send!, turn!, by-id,
    by-channel, env-for, close!, delete!, set-title!.
  - Environment runtime: create-environment, dispose-environment!,
    get-router, rebuild-router!, resolve-effective-model.
  - Extension contract: extension, symbol, value, render-prompt,
    register-extension!, registered-extensions, discovery, reload.
  - Registries: command, channel, provider, and backend registration
    helpers for host-owned and embedded use.
  - Persistence facade: db-* functions and connection helpers. The
    implementation namespace / extension slot are spelled
    `persistance`; human-facing language is Persistence.
  - Prompt / Python-sandbox / formatting / cancellation /
    notifications / doctor helpers shared by channels and extensions.

Not every export is equally high-level. `send!`, extension maps,
registry builders, read-side persistence helpers, and Markdown export
are the preferred integration surface. Low-level sandbox, parse-repair,
dispatcher, and write-side db helpers are exported because this is a
host facade, but ordinary extensions should avoid depending on them
unless they are implementing host-level behavior.

Binary entry: -main (invoked by `clojure -M:vis`, AOT'd to a Java
entry class via `:gen-class` for the GraalVM native-image build).
raw docstring

->astclj

(->ast v)

Soft-normalize any answer-input value into canonical [:ast & blocks]. Pure, total, idempotent.

Identity-preserving: when the input already satisfies the canonical invariants (canonical?), the return value is the SAME object. This keeps downstream System/identityHashCode caches (format-answer-with-thinking-data, etc.) hot across repeated render passes — walker output is computed once per canonical IR identity, not once per equal-but-fresh allocation.

Before canonicalization, Hiccup child positions are walked with clojure+.walk semantics and non-vector sequential values (notably lazy seqs from (map ...) inside renderer input) are safely realized to at most 100 items, then replaced with an explicit … many more marker when truncated. This avoids persisting Java LazySeq identity strings and avoids hanging on infinite seqs.

See namespace docstring for the full canonical-form invariants.

Soft-normalize any answer-input value into canonical [:ast & blocks].
Pure, total, idempotent.

Identity-preserving: when the input already satisfies the canonical
invariants (`canonical?`), the return value is the SAME object.
This keeps downstream `System/identityHashCode` caches
(`format-answer-with-thinking-data`, etc.) hot across repeated
render passes — walker output is computed once per canonical IR
identity, not once per equal-but-fresh allocation.

Before canonicalization, Hiccup child positions are walked with
`clojure+.walk` semantics and non-vector sequential values (notably
lazy seqs from `(map ...)` inside renderer input) are safely realized to
at most 100 items, then replaced with an explicit `… many more`
marker when truncated. This avoids persisting Java LazySeq identity
strings and avoids hanging on infinite seqs.

See namespace docstring for the full canonical-form invariants.
sourceraw docstring

->dateclj

(->date v)
source

->epoch-msclj

(->epoch-ms v)
source

->idclj

(->id v)
source

->jsonclj

(->json m)

Serialize a value to a JSON TEXT column. Nil in, nil out.

Serialize a value to a JSON TEXT column. Nil in, nil out.
sourceraw docstring

->kwclj

(->kw v)

Keyword/string -> TEXT, stripping the leading colon. Nil -> nil.

Keyword/string -> TEXT, stripping the leading colon. Nil -> nil.
sourceraw docstring

->kw-backclj

(->kw-back v)
source

->refclj

(->ref v)

Normalize an entity reference to a string ID for SQL. Accepts: UUID, string, or nil. Returns string or nil.

The ONLY way to extract a SQL-ready string from an entity reference -- pass the plain UUID or string directly.

Normalize an entity reference to a string ID for SQL.
Accepts: UUID, string, or nil. Returns string or nil.

The ONLY way to extract a SQL-ready string from an entity
reference -- pass the plain UUID or string directly.
sourceraw docstring

->svar-modelclj

(->svar-model model)
(->svar-model _provider-id model)

Coerce a model representation to svar-native {:name str}.

Coerce a model representation to svar-native `{:name str}`.
sourceraw docstring

->svar-providerclj

(->svar-provider provider)

Coerce a provider map to svar-native shape (:id, :api-key, :base-url, :api-style, :models, optional :responses-path, optional :llm-headers, and Vis-owned :network request defaults).

Resolve :base-url from configuration or the provider template (registered preset, then svar's catalog). A credential callback's :api-url replaces that URL only when no endpoint is configured or it matches the preset/catalog default; a custom configured endpoint wins. Forward the resolved URL because svar cannot recover extension-only presets.

When :api-key is nil, look the provider up in the global provider registry (registry.clj) and call its :provider/get-token-fn to resolve a usable token. Each provider implementation handles its own auth lifecycle (OAuth refresh, env-var fallback, provider-specific headers, ...) so this fn stays provider-agnostic and never references a concrete provider ns by name.

Coerce a provider map to svar-native shape (`:id`, `:api-key`,
`:base-url`, `:api-style`, `:models`, optional `:responses-path`,
optional `:llm-headers`, and Vis-owned `:network` request defaults).

Resolve `:base-url` from configuration or the provider template
(registered preset, then svar's catalog). A credential callback's
`:api-url` replaces that URL only when no endpoint is configured or it
matches the preset/catalog default; a custom configured endpoint wins.
Forward the resolved URL because svar cannot recover extension-only presets.

When `:api-key` is nil, look the provider up in the global
provider registry (registry.clj) and call its
`:provider/get-token-fn` to resolve a usable token. Each provider
implementation handles its own auth lifecycle (OAuth refresh,
env-var fallback, provider-specific headers, ...) so this fn stays
provider-agnostic and never references a concrete provider ns by
name.
sourceraw docstring

->uuidclj

(->uuid v)
source

-mainclj

(-main & args)

The binary entry; Python workers have their own entrypoint in the runtime.

The binary entry; Python workers have their own entrypoint in the runtime.
sourceraw docstring

<-jsonclj

(<-json s)

Parse a JSON TEXT column. STRINGS-ONLY: keys come back as VERBATIM STRINGS - no :key-fn keyword re-keywordizing. Whatever needs an internal keyword shape converts at ONE named adapter, never here.

Parse a JSON TEXT column. STRINGS-ONLY: keys come back as VERBATIM STRINGS -
no `:key-fn keyword` re-keywordizing. Whatever needs an internal keyword
shape converts at ONE named adapter, never here.
sourceraw docstring

abbreviate-homeclj

(abbreviate-home path)
(abbreviate-home path home)

Shorten an absolute path for DISPLAY by replacing the user's home dir with ~, matching the footer/navigator/dialogs. Only rewrites when path is at or under home (so /etc/x and relative paths stay unchanged). Rendered descendants always use / separators; nil-safe.

Shorten an absolute path for DISPLAY by replacing the user's home dir with
`~`, matching the footer/navigator/dialogs. Only rewrites when `path` is at
or under home (so `/etc/x` and relative paths stay unchanged). Rendered
descendants always use `/` separators; nil-safe.
sourceraw docstring

active-extensionsclj

(active-extensions environment)

Returns the seq of registered extensions whose :ext/activation-fn returns truthy for environment, in registration order. Single source of truth for activation; call ONCE at the top of a turn.

Returns the seq of registered extensions whose `:ext/activation-fn` returns
truthy for `environment`, in registration order. Single source of truth for
activation; call ONCE at the top of a turn.
sourceraw docstring

active-modelclj

(active-model)

Return the primary model name string, or nil.

Return the primary model name string, or nil.
sourceraw docstring

active-providerclj

(active-provider)

Return the first (primary) provider from config, or nil.

Return the first (primary) provider from config, or nil.
sourceraw docstring

active-slashesclj

(active-slashes env)

Aggregate :ext/slash-commands from every active extension for env. Order: extension registration order (stable). Returns a vec.

This is the ONLY source of truth for engine slash dispatch (which already has a turn env handy). Channels that lack a per-turn env should use registered-slashes (no activation filtering).

Aggregate `:ext/slash-commands` from every active extension for `env`.
Order: extension registration order (stable). Returns a vec.

This is the ONLY source of truth for engine slash dispatch (which
already has a turn env handy). Channels that lack a per-turn env
should use `registered-slashes` (no activation filtering).
sourceraw docstring

add-channel-event-listener!clj

source

add-config-provider!clj

(add-config-provider! provider-cfg)
(add-config-provider! provider-cfg source)

Append a provider config to the persisted fleet (no-op when its id exists).

Append a provider config to the persisted fleet (no-op when its id exists).
sourceraw docstring

add-python-extension-change-listener!clj

(add-python-extension-change-listener! listener-id f)

Subscribe f to Python-extension set changes. f receives {:extensions [<validated ext map> ...] :removed [<ext-name> ...]} after every (re)load that changed anything: :extensions is the full freshly-registered set, :removed the names that no longer exist. Re-registering the same listener-id replaces the old listener. Returns listener-id.

Subscribe `f` to Python-extension set changes. `f` receives
`{:extensions [<validated ext map> ...] :removed [<ext-name> ...]}`
after every (re)load that changed anything: `:extensions` is the full
freshly-registered set, `:removed` the names that no longer exist.
Re-registering the same `listener-id` replaces the old listener.
Returns `listener-id`.
sourceraw docstring

add-title-listener!clj

(add-title-listener! session-id listener-fn)

Register listener-fn for session-id. The fn is invoked with the new title (a string) every time the title changes. Multiple listeners are supported; they fire in unspecified order.

Returns the listener fn so callers can pass it to remove-title-listener! later.

Register `listener-fn` for `session-id`. The fn is invoked with
the new title (a string) every time the title changes. Multiple
listeners are supported; they fire in unspecified order.

Returns the listener fn so callers can pass it to
`remove-title-listener!` later.
sourceraw docstring

add-title-pending-listener!clj

(add-title-pending-listener! session-id listener-fn)

Register listener-fn for session-id; invoked with a boolean (true when title generation starts, false when it ends). Returns the listener fn for later remove-title-pending-listener!.

Register `listener-fn` for `session-id`; invoked with a boolean
(true when title generation starts, false when it ends). Returns the
listener fn for later `remove-title-pending-listener!`.
sourceraw docstring

all-provider-limitsclj

(all-provider-limits)

Return normalized limits reports for every registered provider in registration order.

Return normalized limits reports for every registered provider in
registration order.
sourceraw docstring

ask-code!clj

(ask-code! opts)

One-shot routed svar/ask-code! against the global router. Plain-text completion + Markdown-code-block extraction — returns the svar map {:blocks :raw :reasoning :tokens :cost :duration-ms :assistant-message :provider-state}. :blocks is a vec of {:lang :source} (one entry per Markdown code block); concatenate yourself with svar.internal.codes/concat-sources if you need a single string. ask! (JSON-spec) is gone; every Vis caller uses ask-code!.

One-shot routed `svar/ask-code!` against the global router.
Plain-text completion + Markdown-code-block extraction — returns the
svar map `{:blocks :raw :reasoning :tokens :cost :duration-ms
:assistant-message :provider-state}`. `:blocks` is a vec of
`{:lang :source}` (one entry per Markdown code block); concatenate
yourself with `svar.internal.codes/concat-sources` if you need a
single string. `ask!` (JSON-spec) is gone; every Vis caller uses
`ask-code!`.
sourceraw docstring

assemble-initial-messagesclj

(assemble-initial-messages
  {:keys [stable-prompt-messages initial-user-content previous-turn-context
          turn-context user-images skipped-images vision? image-descriptions]
   :or {vision? true}})

Initial provider messages for one turn.

Prior RESUME entries are emitted as one stable user message per turn (or materialized fold checkpoint), so adding a turn appends a message instead of rewriting one monolithic conversation recap. :turn-context is the current append-only turn/utilization assignment block and rides immediately before the current user request.

:image-descriptions carries the vision fallback's {label {:text … :model …}} for images this turn's target cannot see. Pure input: deciding whether that report is worth paying for belongs to the caller, never to message assembly.

Initial provider messages for one turn.

Prior RESUME entries are emitted as one stable user message per turn (or
materialized fold checkpoint), so adding a turn appends a message instead of
rewriting one monolithic conversation recap. `:turn-context` is the current
append-only turn/utilization assignment block and rides immediately before
the current user request.

`:image-descriptions` carries the vision fallback's `{label {:text … :model …}}`
for images this turn's target cannot see. Pure input: deciding whether that
report is worth paying for belongs to the caller, never to message assembly.
sourceraw docstring

assemble-stable-prompt-messagesclj

(assemble-stable-prompt-messages
  environment
  {:keys [system-prompt active-extensions session-context] :as opts})

Assemble provider-prefix messages.

Send order is explicit and tested: SYSTEM-PROMPT - CORE_SYSTEM_PROMPT + caller addendum PROJECT-INSTRUCTIONS - AGENTS.md / CLAUDE.md contents (when present) TURN-SYSTEM-CONTEXT - turn-scoped runtime capability context. Today it contains extension prompt fragments; future message, never append a second extension context.

Extension fragments are separate from the core system prompt and are not repeated in per-iteration trailers.

Required opts: :active-extensions - vec from (active-extensions env). Drives environment, extension prompt, and hint collection.

Optional opts: :system-prompt - caller addendum appended to CORE. :session-context - rendered fenced-Python session = {…} block (standing session state: workspace / env / routing / tools). Embedded ONCE here as a cached system message; the loop re-emits only the session[...] = … structural delta in the conversation when it changes mid-turn.

Assemble provider-prefix messages.

Send order is explicit and tested:
  `SYSTEM-PROMPT`         - CORE_SYSTEM_PROMPT + caller addendum
  `PROJECT-INSTRUCTIONS`  - AGENTS.md / CLAUDE.md contents (when present)
  `TURN-SYSTEM-CONTEXT`   - turn-scoped runtime capability context. Today
                            it contains extension prompt fragments; future
                            message, never append a second extension
                            context.

Extension fragments are separate from the core system prompt and are not
repeated in per-iteration trailers.

Required opts:
  `:active-extensions` - vec from `(active-extensions env)`. Drives
     environment, extension prompt, and hint collection.

Optional opts:
  `:system-prompt`            - caller addendum appended to CORE.
  `:session-context`          - rendered fenced-Python `session = {…}` block
     (standing session state: workspace / env / routing / tools). Embedded
     ONCE here as a cached system message; the loop re-emits only the
     `session[...] = …` structural delta in the conversation when it changes
     mid-turn.
sourceraw docstring

audio-transcribe-outcomeclj

(audio-transcribe-outcome attachment)

What is known about this recording's words RIGHT NOW, without starting anything.

{:transcription "…"} once they exist, {:status "pending"} while the worker has it, a settled {:status …} when it could not be made, and nil when nobody has asked yet — which is what a composer paints as a placeholder and re-reads on the next frame.

What is known about this recording's words RIGHT NOW, without starting anything.

`{:transcription "…"}` once they exist, `{:status "pending"}` while the worker
has it, a settled `{:status …}` when it could not be made, and nil when nobody has
asked yet — which is what a composer paints as a placeholder and re-reads on the
next frame.
sourceraw docstring

audio-transcribe-request!clj

(audio-transcribe-request! attachments)

Start the words for every recording in attachments and answer the rows with whatever is known NOW — normally pending.

NOTHING waits. This is the call a surface makes the moment files are staged, and the one the turn makes when attachments first land, so the speech is already being made while the human is still typing and while the rest of the turn is assembled.

Start the words for every recording in `attachments` and answer the rows with
whatever is known NOW — normally `pending`.

NOTHING waits. This is the call a surface makes the moment files are staged, and
the one the turn makes when attachments first land, so the speech is already being
made while the human is still typing and while the rest of the turn is assembled.
sourceraw docstring

audio-transcribe-statusesclj

The CLOSED vocabulary of what a surface may be told about a recording whose words it does not have. A row that carries :transcription carries no status at all.

The CLOSED vocabulary of what a surface may be told about a recording whose words
it does not have. A row that carries `:transcription` carries no status at all.
sourceraw docstring

authenticated-preset-providersclj

(authenticated-preset-providers)

Registered providers that BIND THEMSELVES — the credential lives OUTSIDE the persisted fleet, so the provider is usable with no Add provider step at all. Shaped as minimal picker rows ({:id … :models …} carrying the preset's default catalog models) and appended by picker-fleet.

Two ways in. A MANAGED provider ([[managed?]]) binds because its runtime issues the credential: there is nothing local to probe and nothing a human could add. Every other provider binds only when its OWN :provider/detect-fn (local, no network) finds one — an OAuth token file, a keychain entry.

A provider with neither, or with no default models, is skipped.

Registered providers that BIND THEMSELVES — the credential lives OUTSIDE the
persisted fleet, so the provider is usable with no `Add provider` step at all.
Shaped as minimal picker rows (`{:id … :models …}` carrying the preset's
default catalog models) and appended by [[picker-fleet]].

Two ways in. A MANAGED provider ([[managed?]]) binds because its runtime
issues the credential: there is nothing local to probe and nothing a human
could add. Every other provider binds only when its OWN `:provider/detect-fn`
(local, no network) finds one — an OAuth token file, a keychain entry.

A provider with neither, or with no default models, is skipped.
sourceraw docstring

available-theme-idsclj

(available-theme-ids)
(available-theme-ids extensions)

Theme ids from the process registry plus optional unregistered extension descriptor maps. Normally extensions are already installed into themes by register-extension!; the argument remains for pure tests/previews.

vis-light/vis-dark are pinned to the top (see theme-id-priority); all other ids follow, sorted alphabetically.

Theme ids from the process registry plus optional unregistered extension
descriptor maps. Normally extensions are already installed into `themes`
by `register-extension!`; the argument remains for pure tests/previews.

`vis-light`/`vis-dark` are pinned to the top (see `theme-id-priority`);
all other ids follow, sorted alphabetically.
sourceraw docstring

beautify-pythonclj

(beautify-python code)

ruff-format code (cached). nil/blank -> "". Never throws — falls back to the verbatim source when ruff can't format or isn't available.

ruff-format `code` (cached). nil/blank -> "". Never throws — falls back to
the verbatim source when ruff can't format or isn't available.
sourceraw docstring

bind-and-bump!clj

(bind-and-bump! env sym val)

Set sym -> val in the env's sandbox.

Set `sym` -> `val` in the env's sandbox.
sourceraw docstring

build-system-promptclj

(build-system-prompt {:keys [system-prompt workspace-root]})

Core system prompt + optional caller addendum + config prompt + SYSTEM.md / APPEND_SYSTEM.md file overrides.

Assembled in send order (later blocks positionally reinforce earlier): base, then the caller's :system-prompt addendum, then the :system-prompt pulled from Vis config (~/.vis/config.yml / state.yml / <project>/vis.yml / .vis/config.yml, deep-merged), then ~/.vis/APPEND_SYSTEM.md, then <workspace>/.vis/APPEND_SYSTEM.md. The config + file hooks let a project append house rules without any caller having to pass them.

Full rewrite precedence for the base: <workspace>/.vis/SYSTEM.md > ~/.vis/SYSTEM.md > config :system-prompt map with :replace? true > CORE_SYSTEM_PROMPT. When a file/config replaces the base, addenda and append files are still appended after it. workspace-root scopes all project config and file lookups; an omitted root keeps the caller's workspace binding.

Core system prompt + optional caller addendum + config prompt +
SYSTEM.md / APPEND_SYSTEM.md file overrides.

Assembled in send order (later blocks positionally reinforce earlier):
base, then the caller's `:system-prompt` addendum, then the
`:system-prompt` pulled from Vis config (`~/.vis/config.yml` / `state.yml` /
`<project>/vis.yml` / `.vis/config.yml`, deep-merged), then `~/.vis/APPEND_SYSTEM.md`, then
`<workspace>/.vis/APPEND_SYSTEM.md`. The config + file hooks let a project
append house rules without any caller having to pass them.

Full rewrite precedence for the base: `<workspace>/.vis/SYSTEM.md` >
`~/.vis/SYSTEM.md` > config `:system-prompt` map with `:replace? true` >
`CORE_SYSTEM_PROMPT`. When a file/config replaces the base, addenda and
append files are still appended after it. `workspace-root` scopes all project
config and file lookups; an omitted root keeps the caller's workspace binding.
sourceraw docstring

by-channelclj

(by-channel channel)
source

by-cmdclj

(by-cmd cmd)

Lookup the channel whose :channel/cmd equals cmd. Returns nil when no channel claims that command.

Lookup the channel whose :channel/cmd equals `cmd`. Returns nil
when no channel claims that command.
sourceraw docstring

by-idclj

(by-id id)

Return the session record (UUID :id) or nil.

Return the session record (UUID `:id`) or nil.
sourceraw docstring

cache-env!clj

(cache-env! session-id env)

Insert env into the cache under session-id (UUID, or string normalized via cache-key). Returns {:id <UUID> :environment env}.

Insert `env` into the cache under `session-id` (UUID, or string
normalized via `cache-key`). Returns `{:id <UUID> :environment env}`.
sourceraw docstring

call-env-valuesclj

(call-env-values env)

Resolve ONE call's env delta into {NAME value-or-nil}, where nil means UNSET that name for this child. A DELTA: it is merged over the project environment (config/child-environment-values), never a replacement for it, so a workspace .env still reaches a child whose call names one variable.

A value is either a LITERAL (string/number/boolean) or a SOURCE map — the same {env|dotenv|keychain|command|literal} shape environment: declares. That split is not style: this map is an ARGUMENT, so a literal is written into the session journal and the transcript for good. Literals are for SWITCHES (NODE_ENV, RUST_LOG, PYTHONHASHSEED); a secret names its source and only the child ever sees the value.

Every refusal is LOUD and names the key: a name that is not a variable name, a [[pre-exec-hijack?]] name (which the jail would drop anyway, silently), a map naming no source, and a source that produced nothing — an explicit request for ONE variable that resolved to nothing is an error here, not the quiet :unset a standing declaration is allowed.

Resolve ONE call's `env` delta into `{NAME value-or-nil}`, where nil means
UNSET that name for this child. A DELTA: it is merged over the project
environment (`config/child-environment-values`), never a replacement for it,
so a workspace `.env` still reaches a child whose call names one variable.

A value is either a LITERAL (string/number/boolean) or a SOURCE map — the
same `{env|dotenv|keychain|command|literal}` shape `environment:` declares. That
split is not style: this map is an ARGUMENT, so a literal is written into the
session journal and the transcript for good. Literals are for SWITCHES
(`NODE_ENV`, `RUST_LOG`, `PYTHONHASHSEED`); a secret names its source and
only the child ever sees the value.

Every refusal is LOUD and names the key: a name that is not a variable name,
a [[pre-exec-hijack?]] name (which the jail would drop anyway, silently), a
map naming no source, and a source that produced nothing — an explicit
request for ONE variable that resolved to nothing is an error here, not the
quiet `:unset` a standing declaration is allowed.
sourceraw docstring

cancel!clj

(cancel! token)
(cancel! token reason)

Abort the in-flight turn. Flips the cooperative flag and runs every registered on-cancel! callback exactly once. Each callback is wrapped in its own try/catch so one bad consumer cannot starve the rest.

The callback list is atomically drained before callbacks run. Repeated stops from a user, watchdog, or shutdown therefore preserve the first reason without re-entering a turn's terminal/unwind path.

reason names the ORIGIN (:client-cancel-turn, :stall-watchdog, :gateway-shutdown, …). The first one wins and is read back with [[cancel-reason]]. The one-arity call records :unspecified.

Abort the in-flight turn. Flips the cooperative flag and runs every registered
`on-cancel!` callback exactly once. Each callback is wrapped in its own
`try`/`catch` so one bad consumer cannot starve the rest.

The callback list is atomically drained before callbacks run. Repeated stops
from a user, watchdog, or shutdown therefore preserve the first reason without
re-entering a turn's terminal/unwind path.

`reason` names the ORIGIN (`:client-cancel-turn`, `:stall-watchdog`,
`:gateway-shutdown`, …). The first one wins and is read back with
[[cancel-reason]]. The one-arity call records `:unspecified`.
sourceraw docstring

cancellation-atomclj

(cancellation-atom token)

Cooperative flag atom — read with @ at iteration boundaries when the consumer can return without external help.

Cooperative flag atom — read with `@` at iteration boundaries when
the consumer can return without external help.
sourceraw docstring

cancellation-set-future!clj

(cancellation-set-future! token fut)

Register a worker Future so cancel! interrupts it. Thin convenience over on-cancel!: wraps .cancel(true) in a thunk and discards the returned dispose! (the future's own completion makes the second cancel a no-op).

Returns the future for convenient threading.

Register a worker `Future` so `cancel!` interrupts it. Thin
convenience over `on-cancel!`: wraps `.cancel(true)` in a thunk
and discards the returned `dispose!` (the future's own completion
makes the second cancel a no-op).

Returns the future for convenient threading.
sourceraw docstring

cancellation-tokenclj

(cancellation-token)

Construct a fresh cancellation token.

The token bundles three things every cancellable boundary needs:

  • ::flag — cooperative boolean atom, polled at iteration boundaries by callers that can return gracefully.
  • ::callbacks — vec of [id thunk] pairs run by cancel! so any number of in-flight workers (provider HTTP call, Python eval future, voice recorder) can register their own hard-cancel hook.
  • ::reason — WHO fired the cancel, stamped by cancel! and read back with cancel-reason. Downstream every cancel looks identical (a thread interrupt), so without this stamp a self-inflicted cancel (stall watchdog, shutdown) is indistinguishable from a user Esc.

cancellation-set-future! (legacy single-future API) is kept for call sites that have not migrated yet; it now routes through the callback registry too so behaviour stays identical.

Construct a fresh cancellation token.

The token bundles three things every cancellable boundary needs:
  - `::flag`      — cooperative boolean atom, polled at iteration
                     boundaries by callers that can return
                     gracefully.
  - `::callbacks` — vec of `[id thunk]` pairs run by `cancel!` so
                     any number of in-flight workers (provider
                     HTTP call, Python eval future, voice recorder)
                     can register their own hard-cancel hook.
  - `::reason`    — WHO fired the cancel, stamped by `cancel!` and read
                     back with `cancel-reason`. Downstream every cancel
                     looks identical (a thread interrupt), so without
                     this stamp a self-inflicted cancel (stall watchdog,
                     shutdown) is indistinguishable from a user Esc.

`cancellation-set-future!` (legacy single-future API) is kept for
call sites that have not migrated yet; it now routes through the
callback registry too so behaviour stays identical.
sourceraw docstring

cancellation?clj

(cancellation? e)

True if the given throwable was caused by a cancel! call. Channels should treat this as a normal (cancelled) outcome rather than an error and avoid showing stack traces.

True if the given throwable was caused by a `cancel!` call. Channels
should treat this as a normal (cancelled) outcome rather than an
error and avoid showing stack traces.
sourceraw docstring

cancelled?clj

(cancelled? token)

True once cancel! has been called on this token.

True once `cancel!` has been called on this token.
sourceraw docstring

capability-ensure!clj

(capability-ensure! id probe)

This process's verdict for capability id, probing at most once per answer that cannot change:

{:capability id :status :ready :detail <whatever the probe returned>} {:capability id :status :unavailable :kind :terminal|:transient :error <message> :cause <throwable>}

probe is a thunk that DOES the real thing and throws when the machine cannot: link the library, open the device, run the binary. It is called at most once while a :ready or :terminal verdict stands, and again after a :transient one. Probes are serialized against each other, because two callers racing to download the same 13 MB is the failure this replaces.

This process's verdict for capability `id`, probing at most once per answer that
cannot change:

  {:capability id :status :ready       :detail <whatever the probe returned>}
  {:capability id :status :unavailable :kind :terminal|:transient
   :error <message> :cause <throwable>}

`probe` is a thunk that DOES the real thing and throws when the machine cannot:
link the library, open the device, run the binary. It is called at most once
while a `:ready` or `:terminal` verdict stands, and again after a `:transient`
one. Probes are serialized against each other, because two callers racing to
download the same 13 MB is the failure this replaces.
sourceraw docstring

capability-fail!clj

(capability-fail! id t)

Record a TERMINAL failure met somewhere other than the probe, and answer the verdict now in force.

A native runtime rarely breaks where it is provisioned: the library loads from the static initializer of the first class that touches it, so the linker speaks from inside the call, long after ensure! answered :ready. Without this, every later call re-provisions and re-fails; with it, the next ensure! says restart. A transient failure is NOT recorded — only the JVM's own frozen answers are.

Record a TERMINAL failure met somewhere other than the probe, and answer the
verdict now in force.

A native runtime rarely breaks where it is provisioned: the library loads from
the static initializer of the first class that touches it, so the linker speaks
from inside the call, long after `ensure!` answered `:ready`. Without this, every
later call re-provisions and re-fails; with it, the next `ensure!` says restart.
A transient failure is NOT recorded — only the JVM's own frozen answers are.
sourceraw docstring

capability-forget-verdicts!clj

(capability-forget-verdicts!)

Forget every verdict. The seam a TEST drives — production never calls it, because a remembered verdict is exactly the answer this process can no longer change.

Forget every verdict. The seam a TEST drives — production never calls it, because
a remembered verdict is exactly the answer this process can no longer change.
sourceraw docstring

capability-terminal-error?clj

(capability-terminal-error? t)

True when t is the JVM refusing to LINK, at any depth: a native library is missing, or a class that already met a missing library is permanently unusable. The walk STOPS at the end of the cause chain — a shallow failure must not become a NullPointerException out of the very code that explains it.

True when `t` is the JVM refusing to LINK, at any depth: a native library is
missing, or a class that already met a missing library is permanently unusable.
The walk STOPS at the end of the cause chain — a shallow failure must not become
a NullPointerException out of the very code that explains it.
sourceraw docstring

capability-verdictclj

(capability-verdict id)

The verdict this process already reached for id, or nil when it has never been asked. NEVER probes: this is what a status line or a doctor check reads, and a diagnostic that provisions 13 MB of natives to print one line is a bug.

The verdict this process already reached for `id`, or nil when it has never been
asked. NEVER probes: this is what a status line or a doctor check reads, and a
diagnostic that provisions 13 MB of natives to print one line is a bug.
sourceraw docstring

channelclj

(channel descriptor)

Build and validate a channel descriptor map.

Build and validate a channel descriptor map.
sourceraw docstring

channel-by-idclj

(channel-by-id id)

Lookup the channel by :channel/id. Returns nil when absent.

Lookup the channel by :channel/id. Returns nil when absent.
sourceraw docstring

channel-contributions-forclj

(channel-contributions-for channel-id)
(channel-contributions-for channel-id slot)

Return registered extension channel contributions for channel-id in extension registration order. With slot, return only contributions for that channel slot. Contributions are passive data; the channel owns each slot's fn arity + return contract.

Return registered extension channel contributions for `channel-id` in
extension registration order. With `slot`, return only contributions for
that channel slot. Contributions are passive data; the channel owns each
slot's fn arity + return contract.
sourceraw docstring

channel-event-listenersclj

source

close!clj

(close! id)
source

close-all!clj

(close-all!)
source

colorclj

(color k)
(color theme-map k)

Return RGB vector for palette token k in theme-map (or selected/default theme).

Return RGB vector for palette token `k` in `theme-map` (or selected/default theme).
sourceraw docstring

commandclj

(command descriptor)

Build and validate a command map without realizing dynamic children.

Build and validate a command map without realizing dynamic children.
sourceraw docstring

configured-providersclj

(configured-providers)

The persisted provider fleet (global + project overlay), priority order, catalog metadata applied (base-url/api-style filled in).

The persisted provider fleet (global + project overlay), priority
order, catalog metadata applied (base-url/api-style filled in).
sourceraw docstring

configured-providers-cachedclj

(configured-providers-cached)

Frame/request-frequency read of configured-providers that never re-runs the full enumeration on a warm caller. The enumeration behind config/load-config parses four config files per call — ~200ms on machines with slow file IO — which stalled every TUI footer frame when it ran on the render thread (issue #29).

  • FRESH snapshot → returned as-is (pure atom read).
  • STALE snapshot → returned immediately; a single-flight background refresh replaces it off-thread.
  • COLD (first read / just invalidated) → enumerates synchronously ONCE, so callers always get a real fleet, never a nil-because-cold.
Frame/request-frequency read of `configured-providers` that never re-runs
the full enumeration on a warm caller. The enumeration behind
`config/load-config` parses four config files per call — ~200ms on
machines with slow file IO — which stalled every TUI footer frame when it
ran on the render thread (issue #29).

- FRESH snapshot → returned as-is (pure atom read).
- STALE snapshot → returned immediately; a single-flight background
  refresh replaces it off-thread.
- COLD (first read / just invalidated) → enumerates synchronously ONCE, so
  callers always get a real fleet, never a nil-because-cold.
sourceraw docstring

create!clj

(create! channel)
(create! channel {:keys [title external-id workspace-id]})

Create a brand-new session.

Opts (all optional): :title display title :external-id channel-specific external id :workspace-id pre-spawned workspace to pin the new session to. When omitted, a trunk workspace is auto-minted in create-environment.

Create a brand-new session.

Opts (all optional):
  :title         display title
  :external-id   channel-specific external id
  :workspace-id  pre-spawned workspace to pin the new session to.
                 When omitted, a trunk workspace is auto-minted in
                 create-environment.
sourceraw docstring

create-environmentclj

(create-environment router
                    {:keys [db session channel external-id title workspace-id]})

Creates a vis environment (component) for session lifecycle and querying.

The environment holds:

  • Python sandbox context with custom bindings + bindings cache
  • DB connection (or shared-mem datasource)
  • Router (LLM provider config)
  • Extension registry atom

Params: router - Required. Result of llm/make-router. opts - Map with :db and optional :session, :channel, :external-id, :title.

:db accepted forms: nil - no DB (sandbox-only execution) :memory - ephemeral in-process SQLite DB path string - persistent SQLite DB at path {:path p} - persistent SQLite DB at path {:datasource ds} - caller-owned DataSource (not closed on dispose)

Returns the vis environment map.

Creates a vis environment (component) for session lifecycle and
querying.

The environment holds:
  - Python sandbox context with custom bindings + bindings cache
  - DB connection (or shared-mem datasource)
  - Router (LLM provider config)
  - Extension registry atom

Params:
  `router` - Required. Result of `llm/make-router`.
  `opts`   - Map with `:db` and optional `:session`,
              `:channel`, `:external-id`, `:title`.

  `:db` accepted forms:
    nil               - no DB (sandbox-only execution)
    :memory           - ephemeral in-process SQLite DB
    path string       - persistent SQLite DB at path
    {:path p}         - persistent SQLite DB at path
    {:datasource ds}  - caller-owned DataSource (not closed on dispose)

Returns the vis environment map.
sourceraw docstring

create-python-contextclj

(create-python-context custom-bindings roots-fn network-opts stdin)

Equip ONE session with the sandbox and answer {:python-context :sandbox-ns :initial-ns-keys}.

custom-bindings is {symbol value} — a function becomes a host tool, any other value crosses as data. roots-fn answers the directories the guest may read and write; without it the interpreter keeps whatever policy the process already had. network-opts carries the egress rules. stdin is what the guest reads from sys.stdin, or nil for none.

The order matters and is the same order it has always been: the runtime first, then the names the block may not overwrite, then the tools, then the contracts those tools carry, then discovery, then policy — so every __vis_* name and every seeded module is already BASELINE when the member snapshot is taken, and the model's live-vars view shows only what its own blocks made.

Equip ONE session with the sandbox and answer
`{:python-context :sandbox-ns :initial-ns-keys}`.

`custom-bindings` is `{symbol value}` — a function becomes a host tool, any
other value crosses as data. `roots-fn` answers the directories the guest may
read and write; without it the interpreter keeps whatever policy the process
already had. `network-opts` carries the egress rules. `stdin` is what the
guest reads from `sys.stdin`, or nil for none.

The order matters and is the same order it has always been: the runtime
first, then the names the block may not overwrite, then the tools, then the
contracts those tools carry, then discovery, then policy — so every `__vis_*`
name and every seeded module is already BASELINE when the member snapshot is
taken, and the model's live-vars view shows only what its own blocks made.
sourceraw docstring

current-configclj

(current-config)

Return the current provider config. Loads from disk on first call.

Return the current provider config. Loads from disk on first call.
sourceraw docstring

custom-bindingsclj

(custom-bindings env)

Current custom sandbox bindings {sym -> value}.

Current custom sandbox bindings {sym -> value}.
sourceraw docstring

db-claim-session!clj

(db-claim-session! db-info ref)
source

db-create-connection!clj

(db-create-connection! db-spec)

Open a persistence connection from db-spec.

Common spec forms: nil - no DB (returns nil) :memory - in-memory ephemeral store (backend-defined) "path/to.db" - file-backed store (backend-defined) {:backend :sqlite :path ...} - explicit backend selection {:backend :sqlite :datasource ds} - caller-owned DataSource

Omitting :backend selects default-backend; the facade tags the returned store map with the chosen backend so all subsequent facade calls dispatch correctly.

Open a persistence connection from `db-spec`.

Common spec forms:
  nil              - no DB (returns nil)
  :memory          - in-memory ephemeral store (backend-defined)
  "path/to.db"   - file-backed store (backend-defined)
  {:backend :sqlite :path ...}     - explicit backend selection
  {:backend :sqlite :datasource ds} - caller-owned DataSource

Omitting `:backend` selects `default-backend`; the facade tags the returned
store map with the chosen backend so all subsequent facade calls dispatch
correctly.
sourceraw docstring

db-delete-session-tree!clj

(db-delete-session-tree! db-info id)
source

db-dispose-connection!clj

(db-dispose-connection! store)
source

db-dispose-shared-connection!clj

(db-dispose-shared-connection!)

Close the shared connection if one is open. Idempotent.

Close the shared connection if one is open. Idempotent.
sourceraw docstring

db-error->user-messageclj

(db-error->user-message e)

Translate a persistence exception into something a human can act on. Backend adapters own backend-specific recognition; unknown errors fall back to (ex-message e).

Translate a persistence exception into something a human can act on.
Backend adapters own backend-specific recognition; unknown errors fall
back to `(ex-message e)`.
sourceraw docstring

db-find-session-by-externalclj

(db-find-session-by-external db-info channel ext-id)
source

db-fork-session!clj

(db-fork-session! db-info session-id opts)
source

db-fork-session-at-turn!clj

(db-fork-session-at-turn! db-info session-id opts)
source

db-get-extension-aggregateclj

(db-get-extension-aggregate db-info opts)
source

db-get-sessionclj

(db-get-session db-info ref)
source

db-infoclj

(db-info)

Return the process-wide shared DB connection bound to (config/resolve-db-spec). Thin wrapper over persistance.core/db-shared-connection! that fills in the default db-spec so frontend callers stay clear of config resolution.

Return the process-wide shared DB connection bound to
`(config/resolve-db-spec)`. Thin wrapper over
`persistance.core/db-shared-connection!` that fills in the default db-spec
so frontend callers stay clear of config resolution.
sourceraw docstring

db-latest-session-state-idclj

(db-latest-session-state-id db-info session-id)
source

db-list-extension-aggregatesclj

(db-list-extension-aggregates db-info opts)
source

db-list-iteration-attachmentsclj

(db-list-iteration-attachments db-info iteration-id)
source

db-list-iteration-attachments-metaclj

(db-list-iteration-attachments-meta db-info iteration-id)
source

db-list-iterations-attachmentsclj

(db-list-iterations-attachments db-info iteration-ids)
source

db-list-iterations-attachments-metaclj

(db-list-iterations-attachments-meta db-info iteration-ids)
source

db-list-session-attachmentsclj

(db-list-session-attachments db-info session-id)
source

db-list-session-attachments-metaclj

(db-list-session-attachments-meta db-info session-id)
source

db-list-session-statesclj

(db-list-session-states db-info session-id)
source

db-list-session-turn-iterationsclj

(db-list-session-turn-iterations db-info session-turn-ref)
source

db-list-session-turn-statesclj

(db-list-session-turn-states db-info session-turn-id)
source

db-list-session-turnsclj

(db-list-session-turns db-info session-ref)
source

db-list-session-turns-by-statusclj

(db-list-session-turns-by-status db-info status)
source

db-list-sessionsclj

(db-list-sessions db-info channel)
source

db-list-turn-all-attachmentsclj

(db-list-turn-all-attachments db-info session-turn-soul-id)
source

db-list-turn-attachmentsclj

(db-list-turn-attachments db-info session-turn-soul-id)
source

db-list-turns-attachmentsclj

(db-list-turns-attachments db-info session-turn-soul-ids)
source

db-load-ctx-historyclj

(db-load-ctx-history db-info session-id)
source

db-load-latest-ctxclj

(db-load-latest-ctx db-info session-id)
source

db-log!clj

(db-log! db-info opts)
source

db-read-attachmentclj

(db-read-attachment db-info attachment-id)
source

db-resolve-session-idclj

(db-resolve-session-id db-info sel)
source

db-retry-session-turn!clj

(db-retry-session-turn! db-info session-turn-soul-id opts)
source

(db-search db-info query opts)

Backend-neutral full-text search facade. Delegates to the registered persistence backend, which RENDERS the neutral query DSL into its native full-text query and runs it. No caller passes an engine dialect — only the DSL in search-query-dsl-doc.

query is the DSL — a string (implicit-AND of its words) or a DSL map. opts: :owner-table restrict to one owner table (string) :field restrict to one indexed field (string) :limit max hits (backend default applies when nil)

Returns a vector of hits sorted by relevance (best first), each {:owner-table :owner-id :field :snippet :rank}. Backends MUST honor the DSL; an engine that cannot express a node should degrade it (e.g. :near -> :all), never reject well-formed DSL. A MALFORMED query (e.g. a lone :not) may throw — that is a DSL logic error, distinct from un-matchable content.

Backend-neutral full-text search facade. Delegates to the registered
persistence backend, which RENDERS the neutral query DSL into its native
full-text query and runs it. No caller passes an engine dialect — only the
DSL in `search-query-dsl-doc`.

`query` is the DSL — a string (implicit-AND of its words) or a DSL map.
`opts`:
  :owner-table  restrict to one owner table (string)
  :field        restrict to one indexed field (string)
  :limit        max hits (backend default applies when nil)

Returns a vector of hits sorted by relevance (best first), each
`{:owner-table :owner-id :field :snippet :rank}`. Backends MUST honor the
DSL; an engine that cannot express a node should degrade it (e.g. :near ->
:all), never reject well-formed DSL. A MALFORMED query (e.g. a lone :not)
may throw — that is a DSL logic error, distinct from un-matchable content.
sourceraw docstring

db-search-session-idsclj

(db-search-session-ids db-info channel query)
source

db-search-session-matchesclj

(db-search-session-matches db-info channel query)
source

db-set-turn-attachment-transcription!clj

(db-set-turn-attachment-transcription! db-info
                                       session-turn-soul-id
                                       position
                                       transcription)
source

db-shared-connection!clj

(db-shared-connection! db-spec)

Return the process-wide shared persistence connection for db-spec, opening it on first call and caching the handle for the lifetime of the JVM. Subsequent calls return the cached handle regardless of the db-spec argument - the singleton intentionally pins to the first spec it saw.

Pair with db-dispose-shared-connection! on process shutdown.

Return the process-wide shared persistence connection for `db-spec`,
 opening it on first call and caching the handle for the lifetime of
 the JVM. Subsequent calls return the cached handle regardless of
 the `db-spec` argument - the singleton intentionally pins to the
 first spec it saw.

Pair with `db-dispose-shared-connection!` on process shutdown.
sourceraw docstring

db-store-iteration!clj

(db-store-iteration! db-info opts)

Same delegating shape as the macro-defined fns, but with input validation kept here so every backend gets the same precondition guarantees for free.

Same delegating shape as the macro-defined fns, but with input
validation kept here so every backend gets the same precondition
guarantees for free.
sourceraw docstring

db-store-session!clj

(db-store-session! db-info opts)
source

db-store-session-turn!clj

(db-store-session-turn! db-info opts)
source

db-sweep-orphaned-running-turns!clj

(db-sweep-orphaned-running-turns!)
(db-sweep-orphaned-running-turns! db)

Mark every :running turn as :interrupted. Run at process start to clean up turns that crashed or were killed mid-write so the next turn's handover digest renders the right outcome instead of guessing. Returns the number of turns swept.

Mark every `:running` turn as `:interrupted`. Run at process start
to clean up turns that crashed or were killed mid-write so the next
turn's handover digest renders the right outcome instead of guessing.
Returns the number of turns swept.
sourceraw docstring

db-turn-historyclj

(db-turn-history db-info session-ref)
source

db-update-session-title!clj

(db-update-session-title! db-info ref title)
source

db-update-session-turn!clj

(db-update-session-turn! db-info session-turn-id opts)

Write a turn's terminal outcome. Same delegating shape as the macro-defined fns, with the DIAGNOSTIC text bound here so every backend gets the same guarantee for free: the write that records HOW a turn ended can never be lost to an unbounded error message (see [[max-persisted-error-chars]]).

Write a turn's terminal outcome. Same delegating shape as the macro-defined
fns, with the DIAGNOSTIC text bound here so every backend gets the same
guarantee for free: the write that records HOW a turn ended can never be lost
to an unbounded error message (see [[max-persisted-error-chars]]).
sourceraw docstring

db-workspace-insert!clj

(db-workspace-insert! db-info opts)
source

default-themeclj

source

default-theme-idclj

The built-in theme id used when config has no explicit theme.

The built-in theme id used when config has no explicit theme.
sourceraw docstring

delete!clj

(delete! id)
source

deregister-channel!clj

(deregister-channel! id)
source

deregister-cmd!clj

(deregister-cmd! nm)
(deregister-cmd! parent nm)

Remove a registered command. parent defaults to [] (top-level).

Remove a registered command. `parent` defaults to `[]` (top-level).
sourceraw docstring

deregister-extension!clj

(deregister-extension! ns-sym)

Drop an extension from the global registry AND reverse every side effect register-extension! dispatched: deregister each CLI subcommand, channel, provider, and persistence backend. Returns nil.

Plan caveat: side-effect cleanup on :removed extensions. Used by Stays available for diagnostic surfaces.

Drop an extension from the global registry AND reverse every side
effect `register-extension!` dispatched: deregister each CLI
subcommand, channel, provider, and persistence backend. Returns nil.

Plan caveat: side-effect cleanup on `:removed` extensions. Used by
Stays available for diagnostic surfaces.
sourceraw docstring

deregister-provider!clj

(deregister-provider! id)
source

diff-line-kindclj

(diff-line-kind line)

Classify ONE unified-diff line for channel-neutral colouring: :meta (file headers ---/+++), :hunk (@@), :add (+), :del (-), or :ctx (context / unchanged). The SINGLE classifier both channels share — the TUI maps the kind to an ANSI colour, the web to a CSS class — so a diff fence colours IDENTICALLY in both, from one source of truth (no per-channel copy to drift).

Classify ONE unified-diff line for channel-neutral colouring: `:meta` (file
headers `---`/`+++`), `:hunk` (`@@`), `:add` (`+`), `:del` (`-`), or `:ctx`
(context / unchanged). The SINGLE classifier both channels share — the TUI maps
the kind to an ANSI colour, the web to a CSS class — so a `diff` fence colours
IDENTICALLY in both, from one source of truth (no per-channel copy to drift).
sourceraw docstring

dismiss!clj

(dismiss! id)

Drop the entry with the given id, regardless of its :until deadline. Returns true when an entry was actually removed. Watchers fire when the value changed.

Drop the entry with the given id, regardless of its `:until`
deadline. Returns true when an entry was actually removed.
Watchers fire when the value changed.
sourceraw docstring

dismiss-all!clj

(dismiss-all!)

Drop every notification. Returns the new (empty) vec.

Drop every notification. Returns the new (empty) vec.
sourceraw docstring

dispatch!clj

(dispatch! root args)
(dispatch! root args {:keys [print-fn]})

Resolve the command for args against root, parse the residual tokens against the resolved command's :cmd/args spec, and call its :cmd/run-fn with [parsed-args residual].

When the command lacks :cmd/run-fn and has subcommands, prints help for that level via render-command. When --help/-h is in the residual, also prints help.

Returns: {:status :ok :command cmd :result <whatever run-fn returned>} {:status :help :command cmd :help-text <string>} {:status :no-match :args args}

Resolve the command for `args` against `root`, parse the residual
tokens against the resolved command's `:cmd/args` spec, and call
its `:cmd/run-fn` with `[parsed-args residual]`.

When the command lacks `:cmd/run-fn` and has subcommands, prints
help for that level via `render-command`. When `--help`/`-h` is
in the residual, also prints help.

Returns:
  {:status :ok       :command cmd :result <whatever run-fn returned>}
  {:status :help     :command cmd :help-text <string>}
  {:status :no-match :args args}
sourceraw docstring

display-labelclj

(display-label pid)

Human-readable label for a provider id. Never persisted.

A REGISTERED provider extension owns its own branding (Anthropic (API Key), LM Studio, OpenAI) and wins. For every other id — anything a caller wrote as providers: - id: … in vis.yml — that id IS the author's chosen spelling, so it is echoed VERBATIM.

Provider ids are authored display values. Return them verbatim when no registered metadata supplies a label.

Human-readable label for a provider id. Never persisted.

A REGISTERED provider extension owns its own branding (`Anthropic (API Key)`,
`LM Studio`, `OpenAI`) and wins. For every other id — anything a caller wrote
as `providers: - id: …` in `vis.yml` — that id IS the author's chosen
spelling, so it is echoed VERBATIM.

Provider ids are authored display values. Return them verbatim when no registered
metadata supplies a label.
sourceraw docstring

display-model-nameclj

(display-model-name m)

DISPLAY-ONLY normalization of a model id: path-style ids (google/gemma-4-12b-qat, org/model as LM Studio / HF name them) render with the slashes flattened to dashes (google-gemma-4-12b-qat), so a provider/model label never reads as three ambiguous segments. The wire/config id keeps its slashes — never feed this back to a router or provider. nil-safe; non-strings and blanks return nil.

DISPLAY-ONLY normalization of a model id: path-style ids
(`google/gemma-4-12b-qat`, `org/model` as LM Studio / HF name them)
render with the slashes flattened to dashes (`google-gemma-4-12b-qat`),
so a `provider/model` label never reads as three ambiguous segments.
The wire/config id keeps its slashes — never feed this back to a
router or provider. nil-safe; non-strings and blanks return nil.
sourceraw docstring

dispose-environment!clj

(dispose-environment! environment)

Disposes a vis environment and releases resources. For persistent DBs (created with :path), data is preserved. For disposable DBs, all data is deleted.

Every env owns its DB connection, so disposing one always closes it.

Disposes a vis environment and releases resources. For persistent DBs
(created with `:path`), data is preserved. For disposable DBs, all
data is deleted.

Every env owns its DB connection, so disposing one always closes it.
sourceraw docstring

doctor-exit-codeclj

(doctor-exit-code messages)

Compute the doctor exit code from a vec of messages. 0 / 1 / 2 by max level. Plan Q19/d2.

Compute the doctor exit code from a vec of messages. 0 / 1 / 2 by
max level. Plan Q19/d2.
sourceraw docstring

doctor-format-outputclj

(doctor-format-output messages)
(doctor-format-output messages {:keys [use-ansi?]})

Build the full TTY output from a vec of messages. Empty result prints a placeholder. Caller routes it to stdout. ANSI is auto-detected; pass :use-ansi? to override.

Build the full TTY output from a vec of messages. Empty result
prints a placeholder. Caller routes it to stdout. ANSI is
auto-detected; pass `:use-ansi?` to override.
sourceraw docstring

doctor-startup-hintclj

(doctor-startup-hint)
(doctor-startup-hint environment)

Return a single-line string like ⚠ vis-agent: 2 issues detected - run \vis-agent doctor` for details.when warn/error count > 0; nil otherwise. Caller decides whether to print (skipped when the command being dispatched ISvis-agent doctor`).

Return a single-line string like `⚠ vis-agent: 2 issues detected - run
\`vis-agent doctor\` for details.` when warn/error count > 0;
nil otherwise. Caller decides whether to print (skipped when the
command being dispatched IS `vis-agent doctor`).
sourceraw docstring

dsclj

(ds db-info)
source

env-differenceclj

(env-difference running requested)

Variable NAMES whose value differs between the env a live process is running with and the one a new start asked for. Both sides are FINGERPRINTS, so this compares digests and answers names — the only thing either side may keep.

Variable NAMES whose value differs between the env a live process is running
with and the one a new start asked for. Both sides are FINGERPRINTS, so this
compares digests and answers names — the only thing either side may keep.
sourceraw docstring

env-fingerprintclj

(env-fingerprint values)

{NAME "<digest>"} for one resolved delta — its SHAPE without its values. This is what a status prints and what a REUSED process is compared against, and both of those are read by a model and written to a log, so the value itself can never appear: a name set from a keychain must compare equal to itself and to nothing else. An unset name fingerprints as "unset".

`{NAME "<digest>"}` for one resolved delta — its SHAPE without its values.
This is what a status prints and what a REUSED process is compared against,
and both of those are read by a model and written to a log, so the value
itself can never appear: a name set from a keychain must compare equal to
itself and to nothing else. An unset name fingerprints as "unset".
sourceraw docstring

env-forclj

(env-for id)
source

env-mismatch-refusalclj

(env-mismatch-refusal id running requested)

{:message :differing} when a REPL is already running with an env OTHER than the one this start named, else nil. Every language pack answers this same refusal, because repl_start must mean ONE thing across languages: a live REPL is reused, never silently replaced, and an env it was not started with is a different REPL. Names and digests only — a value never reaches it.

`{:message :differing}` when a REPL is already running with an env OTHER than
the one this start named, else nil. Every language pack answers this same
refusal, because `repl_start` must mean ONE thing across languages: a live
REPL is reused, never silently replaced, and an env it was not started with
is a different REPL. Names and digests only — a value never reaches it.
sourceraw docstring

error-messageclj

(error-message v)

Build an error message string from a Throwable, map, or string.

Build an error message string from a Throwable, map, or string.
sourceraw docstring

extensioncljmacro

(extension spec)

Build extension spec and stamp caller namespace for reload/source tracking.

Build extension spec and stamp caller namespace for reload/source tracking.
sourceraw docstring

extension-aggregate-create!clj

(extension-aggregate-create! env row)

Append one extension-owned aggregate row. Returns the decoded row. Extension id is always filled from current extension callback context.

Append one extension-owned aggregate row. Returns the decoded row.
Extension id is always filled from current extension callback context.
sourceraw docstring

extension-aggregate-getclj

(extension-aggregate-get env query)

Return one extension-owned aggregate row by query, or nil. Defaults to the latest row when the query is not unique.

Return one extension-owned aggregate row by query, or nil. Defaults to the
latest row when the query is not unique.
sourceraw docstring

extension-aggregate-put!clj

(extension-aggregate-put! env row)

Upsert one singleton extension-owned aggregate row for key/kind/scope. Returns the decoded row.

Upsert one singleton extension-owned aggregate row for key/kind/scope.
Returns the decoded row.
sourceraw docstring

extension-delete-aggregate!clj

(extension-delete-aggregate! env query)

Delete extension-owned aggregate rows matching query. Cross-extension delete is impossible through this API because extension id is runtime-filled.

Delete extension-owned aggregate rows matching query. Cross-extension delete
is impossible through this API because extension id is runtime-filled.
sourceraw docstring

extension-env-statusclj

(extension-env-status name)

Source and value metadata for variable name, for EVERY surface that resolves one: the Python extension host, a Clojure extension, the TUI settings row.

Order: an environment: declaration DECIDES — a declared name resolves from the source its own declaration names and from nowhere else. Otherwise the workspace's .env/.env.local answer, and only then the process environment. A blank value is no value, whatever produced it — an operator's explicit FOO= means "not this one".

:source is :env, :dotenv, :keychain, :command, :literal or :unset; :value is nil unless that source produced a non-blank string.

Source and value metadata for variable `name`, for EVERY surface that resolves
one: the Python extension host, a Clojure extension, the TUI settings row.

Order: an `environment:` declaration DECIDES — a declared name resolves from
the source its own declaration names and from nowhere else. Otherwise the
workspace's `.env`/`.env.local` answer, and only then the process environment.
A blank value is no value, whatever produced it — an operator's explicit
`FOO=` means "not this one".

`:source` is `:env`, `:dotenv`, `:keychain`, `:command`, `:literal` or
`:unset`; `:value` is nil unless that source produced a non-blank string.
sourceraw docstring

extension-env-valueclj

(extension-env-value name)

Resolved value for name, or nil when no source produced a non-blank one.

Resolved value for `name`, or nil when no source produced a non-blank one.
sourceraw docstring

extension-list-aggregatesclj

(extension-list-aggregates env query)

List extension-owned aggregate rows. The current extension id is always applied; normal extension code cannot list another extension's rows.

List extension-owned aggregate rows. The current extension id is always
applied; normal extension code cannot list another extension's rows.
sourceraw docstring

extension-source-markers-ofclj

(extension-source-markers-of ns-sym)

Lookup the source markers stored for ns-sym. Returns the marker map ({:source-paths :source-mtime-max :source-hash-sha256}) or nil when the extension was never registered (or its markers computation failed at register time).

Lookup the source markers stored for `ns-sym`. Returns the marker
map (`{:source-paths :source-mtime-max :source-hash-sha256}`) or
nil when the extension was never registered (or its markers
computation failed at register time).
sourceraw docstring

extension-theme-settingsclj

(extension-theme-settings)
(extension-theme-settings theme-registry)

Return a registry in extension :ext/theme compact settings shape.

Return a registry in extension `:ext/theme` compact settings shape.
sourceraw docstring

extension-update-aggregate!clj

(extension-update-aggregate! env query f & args)

Atomic singleton update. Reads the current content for query, applies f, and writes the returned value as :content. Query must include :key and :kind.

Atomic singleton update. Reads the current content for query, applies f, and
writes the returned value as :content. Query must include :key and :kind.
sourceraw docstring

extract-codeclj

(extract-code input)

Walk the AST and return a vector of strings, one per [:code ...] block, in source order. Used by vis-agent --code.

Walk the AST and return a vector of strings, one per [:code ...] block,
in source order. Used by `vis-agent --code`.
sourceraw docstring

extract-textclj

(extract-text input)

Walk the AST and return concatenated plain-text content of all [:p] blocks (inline content stripped). Used by voice TTS.

Walk the AST and return concatenated plain-text content of all [:p]
blocks (inline content stripped). Used by voice TTS.
sourceraw docstring

final-answer-code-error-messageclj

(final-answer-code-error-message exception)
source

find-leafclj

(find-leaf root args)

Walk the tree from root consuming tokens until either:

  • a child matches and has no further subcommands
  • or no child matches the next token

Returns {:command resolved-cmd :path [name...] :residual [token...]}, or nil when even the root's name doesn't match args[0]. The residual is everything LEFT after the resolved command name.

Walk the tree from `root` consuming tokens until either:
  - a child matches and has no further subcommands
  - or no child matches the next token

Returns `{:command resolved-cmd :path [name...] :residual [token...]}`,
or nil when even the root's name doesn't match args[0]. The
residual is everything LEFT after the resolved command name.
sourceraw docstring

find-namedclj

(find-named root args)

Like find-leaf, but matches against the bare arg vector ignoring the root command's name (the way cli/-main typically gets called). Useful when the root is implicit and you just want the resolved subcommand for the given args.

Like `find-leaf`, but matches against the bare arg vector ignoring
the root command's name (the way `cli/-main` typically gets called).
Useful when the root is implicit and you just want the resolved
subcommand for the given args.
sourceraw docstring

first-run?clj

(first-run?)

True on a genuine FIRST run: no provider configured AND no global machine store (~/.vis/state.yml) has ever been written. Distinguishes the full welcome (brand-new user) from a returning user who merely has no provider right now (e.g. removed their only one).

True on a genuine FIRST run: no provider configured AND no global machine store
(`~/.vis/state.yml`) has ever been written. Distinguishes the full welcome
(brand-new user) from a returning user who merely has no provider right now
(e.g. removed their only one).
sourceraw docstring

form->displayclj

(form->display m)

Project canonical display fields from a source map, dropping nils.

Project canonical display fields from a source map, dropping nils.
sourceraw docstring

form-with-displayclj

(form-with-display form)

Attach the cached ruff rendering of a form's Python source when the form did not author its own :display-code. Result presentation is always derived locally from canonical facts and is never attached to the form.

Attach the cached ruff rendering of a form's Python source when the form did not
author its own `:display-code`. Result presentation is always derived locally
from canonical facts and is never attached to the form.
sourceraw docstring

form<-wireclj

(form<-wire event)

Read the canonical display fields back off a gateway WIRE event into a form, using the literal wire spelling declared beside each engine key in display-fields. The single inbound projection channels use — the mirror of ->display.

Read the canonical display fields back off a gateway WIRE event into a form,
using the literal wire spelling declared beside each engine key in
`display-fields`. The single inbound projection channels use — the mirror of
`->display`.
sourceraw docstring

format-clojureclj

(format-clojure code-str _width)

Source is shown as written — no reformatting. Returns code-str trimmed of trailing whitespace (or unchanged when not a string).

Source is shown as written — no reformatting. Returns `code-str`
trimmed of trailing whitespace (or unchanged when not a string).
sourceraw docstring

format-costclj

(format-cost cost)

Render a dollar cost as '~$0.006954' (six decimal places, US locale). Returns nil when cost is nil, zero, negative, or non-numeric. Accepts either the bare number or a "total_cost" map. Detailed cost maps render the total first and the breakdown parenthesized, in order: in, cached, write, out — e.g. '~$0.006954 (in ~$0.001200, cached ~$0.000400, out ~$0.005354)'. The parenthesized breakdown renders only when at least two of those slots carry a positive value; otherwise just the total.

Render a dollar cost as '~$0.006954' (six decimal places, US
locale). Returns nil when `cost` is nil, zero, negative, or
non-numeric. Accepts either the bare number or a `"total_cost"`
map. Detailed cost maps render the total first and the breakdown
parenthesized, in order: in, cached, write, out — e.g.
'~$0.006954 (in ~$0.001200, cached ~$0.000400, out ~$0.005354)'.
The parenthesized breakdown renders only when at least two of
those slots carry a positive value; otherwise just the total.
sourceraw docstring

format-dateclj

(format-date d)

Format a java.util.Date as dd-MM-yyyy HH:mm in local timezone.

Format a `java.util.Date` as `dd-MM-yyyy HH:mm` in local timezone.
sourceraw docstring

format-durationclj

(format-duration ms)

Human-readable millisecond duration. e.g. 2.3s, 1m 15s. Always uses Locale/US so the decimal separator is a dot regardless of the JVM default locale. Coerces the input to long up-front because callers routinely pass a double from (/ ns 1e6).

Human-readable millisecond duration. e.g. `2.3s`, `1m 15s`. Always
uses Locale/US so the decimal separator is a dot regardless of
the JVM default locale. Coerces the input to long up-front because
callers routinely pass a double from `(/ ns 1e6)`.
sourceraw docstring

format-errorclj

(format-error v)

Add the standard ERROR: prefix to an error message, idempotent.

Add the standard `ERROR: ` prefix to an error message, idempotent.
sourceraw docstring

format-iterationsclj

(format-iterations n)
(format-iterations n {:keys [silent-count]})

Render an iteration count as '1 iter' or '3 iters'. Returns nil when n is nil or non-numeric. Optional :silent-count appends hidden/silent bookkeeping count, e.g. '3 iters (2 silent)'.

Render an iteration count as '1 iter' or '3 iters'. Returns nil
when `n` is nil or non-numeric. Optional `:silent-count` appends
hidden/silent bookkeeping count, e.g. '3 iters (2 silent)'.
sourceraw docstring

format-meta-lineclj

(format-meta-line result)
(format-meta-line result opts)

Single-line turn summary for plain-text surfaces (the CLI [...] bracket): the shared meta-summary-line with the fallback note folded inline. The TUI instead uses meta-summary-line + meta-fallback-note directly so it can float the note on its own faint row — same words, same numbers, just two rows. Returns "" when there's nothing to show.

Single-line turn summary for plain-text surfaces (the CLI `[...]` bracket):
the shared `meta-summary-line` with the fallback note
folded inline. The TUI instead uses `meta-summary-line` + `meta-fallback-note`
directly so it can float the note on its own faint row — same words, same
numbers, just two rows. Returns "" when there's nothing to show.
sourceraw docstring

format-tokensclj

(format-tokens {:strs [input output] :as tokens})

Render token counts in the canonical compact grouped form: 'tok <input>→<output> (cached <cached-input>)' when cached input is positive, otherwise 'tok <input>→<output>'.

The arrow reads 'prompt produced completion'. Cached is cached input tokens, parenthesized because provider APIs report cache hits inside prompt usage. Reads the canonical string-keyed usage map ("input" / "output" / "cached" / "cache_created").

Cache visibility: the (cached N) segment renders only when N is positive. Zero / missing cache info stays hidden so meta lines do not show noisy (cached 0) decorations.

Returns nil when no known field carries a number.

Render token counts in the canonical compact grouped form:
'tok <input>→<output> (cached <cached-input>)' when cached input is
positive, otherwise 'tok <input>→<output>'.

The arrow reads 'prompt produced completion'. Cached is cached
input tokens, parenthesized because provider APIs report cache
hits inside prompt usage. Reads the canonical string-keyed usage
map (`"input"` / `"output"` / `"cached"` / `"cache_created"`).

Cache visibility: the `(cached N)` segment renders only when N is
positive. Zero / missing cache info stays hidden so meta lines do
not show noisy `(cached 0)` decorations.

Returns nil when no known field carries a number.
sourceraw docstring

gateway-assign-project!clj

(gateway-assign-project! sid pid)

Assign a session to a project (nil clears / removes from project). Returns the soul.

Assign a session to a project (nil clears / removes from project). Returns the soul.
sourceraw docstring

gateway-attach-turn-sync!clj

(gateway-attach-turn-sync! sid tid {:keys [on-event]})
source

gateway-auth-required?clj

(gateway-auth-required?)

True when this gateway instance demands the bearer token. OFF by default on a loopback bind (a localhost single-user daemon — the token dance is pure friction there); ALWAYS on for a non-loopback bind; --require-token forces it on loopback too.

True when this gateway instance demands the bearer token. OFF by
default on a loopback bind (a localhost single-user daemon — the
token dance is pure friction there); ALWAYS on for a non-loopback
bind; `--require-token` forces it on loopback too.
sourceraw docstring

gateway-cancel-current-turn!clj

(gateway-cancel-current-turn! sid owner-key)

Tid-less cancel: kill the turn currently holding sid's :current-turn slot in the daemon, iff THIS caller submitted it under owner-key (the idempotency_key it sent). For callers that lost (or never learned) the gateway turn id. A session is shared, so an unaddressed cancel would kill whatever another channel happens to be running. Returns the parsed body ({"status" "cancelling", "turn_id" tid}); throws on HTTP error (409 when the session is idle or the running turn is someone else's).

Tid-less cancel: kill the turn currently holding `sid`'s `:current-turn` slot
in the daemon, iff THIS caller submitted it under `owner-key` (the
`idempotency_key` it sent). For callers that lost (or never learned) the
gateway turn id. A session is shared, so an unaddressed cancel would kill
whatever another channel happens to be running. Returns the parsed body
(`{"status" "cancelling", "turn_id" tid}`); throws on HTTP error (409 when
the session is idle or the running turn is someone else's).
sourceraw docstring

gateway-cancel-turn!clj

(gateway-cancel-turn! sid tid)
source

gateway-capabilitiesclj

(gateway-capabilities)

The daemon's capability document, string-keyed, or nil when it cannot answer. The attachment contract a channel admits file drops against comes from here.

The daemon's capability document, string-keyed, or nil when it cannot answer.
The attachment contract a channel admits file drops against comes from here.
sourceraw docstring

gateway-change-root!clj

(gateway-change-root! sid path)

Repoint sid's PRIMARY filesystem root to path IN THE DAEMON, returning the refreshed session-workspace-info (whose :id is the newly pinned workspace).

Repoint `sid`'s PRIMARY filesystem root to `path` IN THE DAEMON, returning the
refreshed `session-workspace-info` (whose `:id` is the newly pinned workspace).
sourceraw docstring

gateway-close-session!clj

(gateway-close-session! sid)
source

gateway-consume-provider-reset-credit!clj

(gateway-consume-provider-reset-credit! provider-id account-id idempotency-key)

Consume the reset confirmed for this account. The caller keeps the same idempotency key until a recognized outcome is received. No route probing or daemon restart is appropriate for a mutation.

Consume the reset confirmed for this account. The caller keeps the same
idempotency key until a recognized outcome is received. No route probing or
daemon restart is appropriate for a mutation.
sourceraw docstring

gateway-context-snapshotclj

(gateway-context-snapshot sid)
source

gateway-create-project!clj

(gateway-create-project! opts)
source

gateway-create-session!clj

(gateway-create-session! opts)
source

gateway-current-seqclj

(gateway-current-seq sid)
source

gateway-cycle-setting!clj

(gateway-cycle-setting! id)

Atomically advance one enum setting in the gateway and return its refreshed string-keyed settings row.

Atomically advance one enum setting in the gateway and return its refreshed
string-keyed settings row.
sourceraw docstring

gateway-daemon-statusclj

(gateway-daemon-status)

Admin status of the gateway this process drives — the REMOTE target when one is configured, else the daemon registered for the current DB. Always the daemon's own wire map (STRING keys), including when nothing is running.

Admin status of the gateway this process drives — the REMOTE target when one is
configured, else the daemon registered for the current DB. Always the daemon's
own wire map (STRING keys), including when nothing is running.
sourceraw docstring

gateway-daemon-stop!clj

(gateway-daemon-stop!)

Stop the daemon registered for this DB, escalating when it stops answering. POST /v1/admin/stop first; when that is met with silence from a daemon that still holds its port, signal the pid the registry names ([[kill-registered-daemon!]]) rather than reporting a live orphan and handing the human an lsof. A port held by a process this registry cannot claim is still reported, never signalled.

Stop the daemon registered for this DB, escalating when it stops answering.
`POST /v1/admin/stop` first; when that is met with silence from a daemon that
still holds its port, signal the pid the registry names ([[kill-registered-daemon!]])
rather than reporting a live orphan and handing the human an `lsof`. A port held
by a process this registry cannot claim is still reported, never signalled.
sourceraw docstring

gateway-delete-project!clj

(gateway-delete-project! pid)
(gateway-delete-project! pid {:keys [is-recursive?]})

DELETE /v1/projects/:pid. Default: member sessions scatter back to project-less. With {:is-recursive? true} every member session is deleted too, and the response names the deleted ids.

DELETE /v1/projects/:pid. Default: member sessions scatter back to
project-less. With `{:is-recursive? true}` every member session is deleted
too, and the response names the deleted ids.
sourceraw docstring

gateway-delete-queued-turn!clj

(gateway-delete-queued-turn! sid tid)
source

gateway-deregister-routes!clj

(gateway-deregister-routes! id)
source

gateway-drain-idle!clj

(gateway-drain-idle! sid)
source

gateway-ensure!clj

(gateway-ensure!)
(gateway-ensure! {:keys [port host] :as opts})

Return a fresh daemon registry entry for the current DB, auto-starting the detached gateway if needed. :memory is a programmer error for this client; headless one-shots stay in-process and should not call here.

Optional :port/:host overrides the bind used WHEN THIS CALL SPAWNS a fresh daemon (e.g. vis-agent channels web --port); a fresh daemon already registered for the DB is a singleton and is attached to as-is, so the override is moot there.

Freshness is DEBOUNCED: the full HTTP /healthz probe (via probe-entry?) runs at most once per entry-probe-ttl-ms. Within that window a cached entry whose pid is still alive is trusted directly, so the TUI's chatty poll loop stops paying for a doubled HTTP round-trip (and its JSON/reflection churn) on every gateway call.

The slow discover/start path is single-flight per canonical DB inside this process. Callers re-check the cache after acquiring that lock, so concurrent startup callbacks share one spawn/wait instead of each waiting for readiness.

A daemon running a DIFFERENT build than this one is also replaced here when replacing it is free ([[bounce-stale-daemon!]]) - that is how the first vis started after vis-agent update, or after a rebuild of a dev checkout, comes up on the new code with nobody stopping anything by hand. That decision comes BEFORE the compatibility assert: a daemon too old to speak this build's wire protocol is the one most worth replacing, so the mismatch screen is left for the daemon somebody is still using.

Return a fresh daemon registry entry for the current DB, auto-starting the
detached gateway if needed. `:memory` is a programmer error for this client;
headless one-shots stay in-process and should not call here.

Optional `:port`/`:host` overrides the bind used WHEN THIS CALL SPAWNS a fresh
daemon (e.g. `vis-agent channels web --port`); a fresh daemon already registered for
the DB is a singleton and is attached to as-is, so the override is moot there.

Freshness is DEBOUNCED: the full HTTP /healthz probe (via `probe-entry?`)
runs at most once per `entry-probe-ttl-ms`. Within that window a cached entry
whose pid is still alive is trusted directly, so the TUI's chatty poll loop
stops paying for a doubled HTTP round-trip (and its JSON/reflection churn) on
every gateway call.

The slow discover/start path is single-flight per canonical DB inside this
process. Callers re-check the cache after acquiring that lock, so concurrent
startup callbacks share one spawn/wait instead of each waiting for readiness.

A daemon running a DIFFERENT build than this one is also replaced here when
replacing it is free ([[bounce-stale-daemon!]]) - that is how the first vis
started after `vis-agent update`, or after a rebuild of a dev checkout, comes up
on the new code with nobody stopping anything by hand. That decision comes BEFORE
the compatibility assert: a daemon too old to speak this build's wire protocol is
the one most worth replacing, so the mismatch screen is left for the daemon
somebody is still using.
sourceraw docstring

gateway-ensure-project-for-root!clj

(gateway-ensure-project-for-root! root)
(gateway-ensure-project-for-root! root name)

POST /v1/projects/actions/ensure — get-or-create the project bound to canonical workspace root (a project IS a TUI tab set). name seeds a fresh project. Returns the project.

POST /v1/projects/actions/ensure — get-or-create the project bound to canonical
workspace `root` (a project IS a TUI tab set). `name` seeds a fresh project.
Returns the project.
sourceraw docstring

gateway-ensure-serving!clj

(gateway-ensure-serving! path)
(gateway-ensure-serving! path opts)

Like [[ensure-gateway!]], but tries to GUARANTEE the returned daemon actually serves path. When [[ensure-gateway!]] attaches to an already-running daemon that 404s on path (started from a classpath missing the extension that owns it), respawn a fresh daemon from THIS process — whose classpath, by construction, carries the route. This is what lets vis-agent channels web self-heal instead of parking on a /ui that 404s.

Optional opts ({:port :host}) overrides the bind used when THIS call has to spawn a fresh daemon (the vis-agent channels web --port/--host flags); it is moot when a fresh daemon is already registered for the DB.

The respawn is NON-DESTRUCTIVE. A blind POST /v1/admin/stop is refcount-blind: it would abort every in-flight turn and kill every session's background resources. So we force-restart the stale daemon ONLY when it is idle — no OTHER clients and no running turn. Otherwise we leave it untouched and surface a clear error. A transport blip on the probe (not a real 404) never triggers a restart. Returns the entry.

Like [[ensure-gateway!]], but tries to GUARANTEE the returned daemon actually
serves `path`. When [[ensure-gateway!]] attaches to an already-running daemon
that 404s on `path` (started from a classpath missing the extension that owns
it), respawn a fresh daemon from THIS process — whose classpath, by
construction, carries the route. This is what lets `vis-agent channels web`
self-heal instead of parking on a `/ui` that 404s.

Optional `opts` (`{:port :host}`) overrides the bind used when THIS call has
to spawn a fresh daemon (the `vis-agent channels web --port/--host` flags); it is
moot when a fresh daemon is already registered for the DB.

The respawn is NON-DESTRUCTIVE. A blind POST /v1/admin/stop is refcount-blind:
it would abort every in-flight turn and kill every session's background
resources. So we force-restart the stale daemon ONLY when it is idle — no OTHER
clients and no running turn. Otherwise we leave it untouched and surface a clear
error. A transport blip on the probe (not a real 404) never triggers a restart.
Returns the entry.
sourceraw docstring

gateway-events-sinceclj

(gateway-events-since sid cursor)
source

gateway-fleet-subscribe!clj

(gateway-fleet-subscribe! sink)

Watch the FLEET stream — GET /v1/events?scope=fleet — and hand every frame to sink. One frame per session whose list-visible state changed (session.status: is_live / is_awaiting_input / current_turn_id) or that was renamed (session.title_updated). Returns a zero-arg stop fn.

This is what a session LIST subscribes to instead of asking about sessions one by one: the fleet answers WHICH sessions changed, so a picker holding a windowed read never polls a row again. There is no replay and no cursor — the feed is a delta layered on a cold /v1/sessions window, so a reconnect costs nothing to arrange and a missed frame heals on the next read. sink runs on the reader thread and must not block it; drops reconnect with the multiplexed mirror's backoff until the returned fn is called.

Watch the FLEET stream — `GET /v1/events?scope=fleet` — and hand every frame
to `sink`. One frame per session whose list-visible state changed
(`session.status`: `is_live` / `is_awaiting_input` / `current_turn_id`) or
that was renamed (`session.title_updated`). Returns a zero-arg stop fn.

This is what a session LIST subscribes to instead of asking about sessions one
by one: the fleet answers WHICH sessions changed, so a picker holding a
windowed read never polls a row again. There is no replay and no cursor — the
feed is a delta layered on a cold `/v1/sessions` window, so a reconnect costs
nothing to arrange and a missed frame heals on the next read. `sink` runs on
the reader thread and must not block it; drops reconnect with the multiplexed
mirror's backoff until the returned fn is called.
sourceraw docstring

gateway-get-projectclj

(gateway-get-project pid)
source

gateway-get-turnclj

(gateway-get-turn sid tid)
source

gateway-input-viewsclj

(gateway-input-views sid)

Pending input Views for sid IN THE DAEMON, oldest first, in canonical wire shape. The live view.open event is the fast path; this is how a client that attached LATER still finds the open form instead of watching a turn that never moves.

Pending input Views for `sid` IN THE DAEMON, oldest first, in
canonical wire shape. The live `view.open` event is the fast path;
this is how a client that attached LATER still finds the open form instead of
watching a turn that never moves.
sourceraw docstring

gateway-iteration-attachment-bytesclj

(gateway-iteration-attachment-bytes sid iid idx)

Raw bytes (a byte-array) of ONE outbound artifact — iteration iid, its 0-based idx in the iteration's ordered attachment list — fetched from the daemon's attachment byte endpoint, or nil (404 / no bytes). The lazy-fetch companion to a live iteration.completed attachment descriptor: a client sees {:index :media_type …} on the frame, then pulls the bytes here. HISTORY resolves the same way (the trace iteration's :id + attachment index).

Raw bytes (a byte-array) of ONE outbound artifact — iteration `iid`, its 0-based
`idx` in the iteration's ordered attachment list — fetched from the daemon's
attachment byte endpoint, or nil (404 / no bytes). The lazy-fetch companion to
a live `iteration.completed` attachment descriptor: a client sees `{:index
:media_type …}` on the frame, then pulls the bytes here. HISTORY resolves the
same way (the trace iteration's `:id` + attachment index).
sourceraw docstring

gateway-list-projectsclj

(gateway-list-projects)
(gateway-list-projects {:keys [owner archived?]})

GET /v1/projects — projects are CROSS-CHANNEL. opts: :owner (string), :archived? (bool). Returns the :projects vector.

GET /v1/projects — projects are CROSS-CHANNEL. `opts`: :owner (string),
:archived? (bool). Returns the :projects vector.
sourceraw docstring

gateway-list-resourcesclj

(gateway-list-resources sid)

Vector of the session's live resource DATA maps from the daemon's registry (string-keyed, same shape resources/list-resources returns in-process).

Vector of the session's live resource DATA maps from the daemon's registry
(string-keyed, same shape `resources/list-resources` returns in-process).
sourceraw docstring

gateway-list-resources-cachedclj

(gateway-list-resources-cached sid)

Footer-frequency read: the session's resource list served from a per-sid cache that NEVER blocks the caller. A stale (or cold) entry kicks a background single-flight refresh and this returns the last-known value immediately (nil before the first success). Keeping the daemon HTTP round-trip OFF the render thread is what stops a busy daemon from stalling every TUI frame.

Footer-frequency read: the session's resource list served from a per-sid cache
that NEVER blocks the caller. A stale (or cold) entry kicks a background
single-flight refresh and this returns the last-known value immediately (nil
before the first success). Keeping the daemon HTTP round-trip OFF the render
thread is what stops a busy daemon from stalling every TUI frame.
sourceraw docstring

gateway-list-sessionsclj

(gateway-list-sessions opts)

The ROWS of one window of the session list, in the gateway's own order. opts names the cut - see session-window-path.

The ROWS of one window of the session list, in the gateway's own order. `opts` names
the cut - see `session-window-path`.
sourceraw docstring

gateway-list-sessions-pageclj

(gateway-list-sessions-page opts)

One window of the session list WITH the walk that continues it: {:sessions rows :next-cursor str-or-nil :has-more bool :total n}.

opts names the cut (session-window-path). A surface that pages - the session picker

  • holds this window and asks for the next one with :after :next-cursor, so a list of a thousand sessions is read a screen at a time instead of downloaded whole.
One window of the session list WITH the walk that continues it:
`{:sessions rows :next-cursor str-or-nil :has-more bool :total n}`.

`opts` names the cut (`session-window-path`). A surface that pages - the session picker
- holds this window and asks for the next one with `:after` `:next-cursor`, so a list of
a thousand sessions is read a screen at a time instead of downloaded whole.
sourceraw docstring

gateway-list-turnsclj

(gateway-list-turns sid)
source

gateway-live-viewsclj

(gateway-live-views sid)

The live views session sid is SHOWING in the daemon right now, oldest first, in canonical wire shape. The view.* events with kind=live are the fast path; this is how a client that attached MID-RUN paints the whole picture at once instead of waiting for the next patch to tell it a view exists.

The live views session `sid` is SHOWING in the daemon right now, oldest first,
in canonical wire shape. The `view.*` events with `kind=live` are the fast path; this
is how a client that attached MID-RUN paints the whole picture at once instead
of waiting for the next patch to tell it a view exists.
sourceraw docstring

gateway-mcp-auth-cancel!clj

(gateway-mcp-auth-cancel! server flow-id)
source

gateway-mcp-auth-complete!clj

(gateway-mcp-auth-complete! server flow-id input)

Finish a flow with the redirect URL the user pasted back (or a bare code).

Finish a flow with the redirect URL the user pasted back (or a bare code).
sourceraw docstring

gateway-mcp-auth-logout!clj

(gateway-mcp-auth-logout! server)

Forget the gateway's persisted OAuth tokens for a server.

Forget the gateway's persisted OAuth tokens for a server.
sourceraw docstring

gateway-mcp-auth-poll!clj

(gateway-mcp-auth-poll! server flow-id)

Read a flow's verdict without blocking: pending, ok, or error.

Read a flow's verdict without blocking: `pending`, `ok`, or `error`.
sourceraw docstring

gateway-mcp-auth-start!clj

(gateway-mcp-auth-start! server)

Begin headless OAuth for an HTTP MCP server. Returns the wire flow (flow_id, kind, url, redirect_uri, expires_at_ms, status).

Begin headless OAuth for an HTTP MCP server. Returns the wire flow
(`flow_id`, `kind`, `url`, `redirect_uri`, `expires_at_ms`, `status`).
sourceraw docstring

gateway-mcp-delete-server!clj

(gateway-mcp-delete-server! server)
source

gateway-mcp-kill-server!clj

(gateway-mcp-kill-server! server)

Stop a server NOW and hold it down until it is started again. Runtime only — nothing in the user's config changes.

Stop a server NOW and hold it down until it is started again. Runtime only —
nothing in the user's config changes.
sourceraw docstring

gateway-mcp-save-server!clj

(gateway-mcp-save-server! server spec)

Create or replace a gateway-managed server. spec is the string-keyed wire spec (transport, command/args/cwd/env, or url/headers, plus the optional enabled and timeout_ms). The DAEMON validates it, persists it in its own machine state, and reconnects — nothing is written on this side, so a TUI attached to a REMOTE gateway adds servers exactly like the app does.

Secrets survive an omitting save: see mcp.core/with-preserved-secrets. Returns the saved sanitized row.

Create or replace a gateway-managed server. `spec` is the string-keyed wire
spec (`transport`, `command`/`args`/`cwd`/`env`, or `url`/`headers`, plus the
optional `enabled` and `timeout_ms`). The DAEMON validates it, persists it in
its own machine state, and reconnects — nothing is written on this side, so a
TUI attached to a REMOTE gateway adds servers exactly like the app does.

Secrets survive an omitting save: see `mcp.core/with-preserved-secrets`.
Returns the saved sanitized row.
sourceraw docstring

gateway-mcp-serversclj

(gateway-mcp-servers)

Sanitized MCP inventory (string-keyed rows: name, transport, enabled, is_connected, is_managed, is_killed, tools, is_authorized, …).

Sanitized MCP inventory (string-keyed rows: `name`, `transport`, `enabled`,
`is_connected`, `is_managed`, `is_killed`, `tools`, `is_authorized`, …).
sourceraw docstring

gateway-mcp-set-server-enabled!clj

(gateway-mcp-set-server-enabled! server enabled)

Persist a server's on/off switch in the gateway's own state.

Persist a server's on/off switch in the gateway's own state.
sourceraw docstring

gateway-mcp-start-server!clj

(gateway-mcp-start-server! server)

Release a kill and connect the server again.

Release a kill and connect the server again.
sourceraw docstring

gateway-mcp-test-server!clj

(gateway-mcp-test-server! server spec)

Connect a CANDIDATE spec without saving it and return {name, is_connected, tools}. The gateway opens and closes the connection, so a bad command or an unreachable endpoint is reported before it is ever persisted.

Connect a CANDIDATE spec without saving it and return `{name, is_connected,
tools}`. The gateway opens and closes the connection, so a bad command or an
unreachable endpoint is reported before it is ever persisted.
sourceraw docstring

gateway-mux-subscribe!clj

(gateway-mux-subscribe! sid sink cursor)

Add sid's sink to the ONE process-wide multiplexed event stream, starting at cursor (its current-seq for a live-only stream). The connection is (re)opened only when the session set changes; multiple local listeners for the SAME session share one cursor and one remote subscription. Returns a zero-arg cleanup fn. Every sink sees gateway.connected / gateway.disconnected on connection changes.

Add `sid`'s `sink` to the ONE process-wide multiplexed event stream, starting
at `cursor` (its `current-seq` for a live-only stream). The connection is
(re)opened only when the session set changes; multiple local listeners for
the SAME session share one cursor and one remote subscription. Returns a
zero-arg cleanup fn. Every sink sees gateway.connected / gateway.disconnected
on connection changes.
sourceraw docstring

gateway-mux-unsubscribe!clj

(gateway-mux-unsubscribe! sid)
(gateway-mux-unsubscribe! sid sub-id)

Drop one local listener from the multiplexed stream and reconnect only when the last listener for that sid is gone (or tear the connection down when it was the last watched session).

Drop one local listener from the multiplexed stream and reconnect only when
the last listener for that sid is gone (or tear the connection down when it
was the last watched session).
sourceraw docstring

gateway-prepare-speech-model!clj

(gateway-prepare-speech-model! direction
                               {:keys [engine-id voice-id on-progress]})

Prepare one gateway-owned speech engine and wait until it is ready. direction is :transcribe or :synthesize; on-progress receives the gateway's string-keyed model state. No model or native runtime is initialized here.

Prepare one gateway-owned speech engine and wait until it is ready. `direction`
is `:transcribe` or `:synthesize`; `on-progress` receives the gateway's
string-keyed model state. No model or native runtime is initialized here.
sourceraw docstring

gateway-provider-auth-cancel!clj

(gateway-provider-auth-cancel! provider-id flow-id)

Forget an abandoned flow. Idempotent.

Forget an abandoned flow. Idempotent.
sourceraw docstring

gateway-provider-auth-complete!clj

(gateway-provider-auth-complete! provider-id flow-id redirect-url)

Finish a pkce flow with the redirect URL the user pasted back.

Finish a `pkce` flow with the redirect URL the user pasted back.
sourceraw docstring

gateway-provider-auth-poll!clj

(gateway-provider-auth-poll! provider-id flow-id)

Read a device flow's verdict: pending, ok, or error. Never blocks.

Read a `device` flow's verdict: `pending`, `ok`, or `error`. Never blocks.
sourceraw docstring

gateway-provider-auth-start!clj

(gateway-provider-auth-start! provider-id)

Begin OAuth for provider-id. Returns the string-keyed wire flow (flow_id, kind, url, user_code, verification_uri, interval_ms, instructions) or nil when the daemon refused.

Begin OAuth for `provider-id`. Returns the string-keyed wire flow
(`flow_id`, `kind`, `url`, `user_code`, `verification_uri`, `interval_ms`,
`instructions`) or nil when the daemon refused.
sourceraw docstring

gateway-provider-auth-submit-key!clj

(gateway-provider-auth-submit-key! provider-id flow-id api-key)

Finish an api-key flow: hand the key the user typed to the DAEMON, which persists it in ITS OWN config. The calling process never writes the credential — same boundary as OAuth.

Finish an `api-key` flow: hand the key the user typed to the DAEMON, which
persists it in ITS OWN config. The calling process never writes the
credential — same boundary as OAuth.
sourceraw docstring

gateway-provider-limitsclj

(gateway-provider-limits provider-id)
source

gateway-provider-logout!clj

(gateway-provider-logout! provider-id)

Clear provider-id's persisted credentials IN THE DAEMON.

Clear `provider-id`'s persisted credentials IN THE DAEMON.
sourceraw docstring

gateway-provider-model-optionsclj

(gateway-provider-model-options provider-id show-all?)

GET /v1/providers/:id/models — the LIVE model catalog resolved DAEMON-side, where the gateway owns OAuth token resolution. A thin client NEVER builds a token-resolving svar router to list models; it asks the daemon, which runs the svar/models! probe (and any token refresh) against its own credential. Returns the engine-shaped {:models [id …] :hidden-count n}.

GET /v1/providers/:id/models — the LIVE model catalog resolved DAEMON-side,
where the gateway owns OAuth token resolution. A thin client NEVER builds a
token-resolving svar router to list models; it asks the daemon, which runs
the `svar/models!` probe (and any token refresh) against its own credential.
Returns the engine-shaped `{:models [id …] :hidden-count n}`.
sourceraw docstring

gateway-provider-remove!clj

(gateway-provider-remove! provider-id)

DELETE /v1/providers/:id — drop provider-id from the fleet IN THE DAEMON, credential included. Removal is the daemon's to do because it owns BOTH the config file and the token file: a row dropped while its credential stays on disk comes straight back as an authenticated preset. Idempotent — is_removed is false when the id was not in the persisted fleet.

DELETE /v1/providers/:id — drop `provider-id` from the fleet IN THE DAEMON,
credential included. Removal is the daemon's to do because it owns BOTH the
config file and the token file: a row dropped while its credential stays on
disk comes straight back as an authenticated preset. Idempotent — `is_removed`
is false when the id was not in the persisted fleet.
sourceraw docstring

gateway-provider-statusclj

(gateway-provider-status provider-id)
source

gateway-reconcile-running-turns!clj

(gateway-reconcile-running-turns!)

Clients do not sweep. Only the daemon may reconcile its own startup orphans.

Clients do not sweep. Only the daemon may reconcile its own startup orphans.
sourceraw docstring

gateway-register-contributed-sse!clj

(gateway-register-contributed-sse! stream-id close!)

Count a contributed SSE connection in the gateway's existing client lifecycle.

Count a contributed SSE connection in the gateway's existing client lifecycle.
sourceraw docstring

gateway-register-routes!clj

(gateway-register-routes! id contribution)

Imperative escape hatch: register (or replace, by id) a route contribution from an embedded/REPL caller. Extensions should prefer the declarative :gateway.slot/http-routes channel-contribution slot — the gateway pulls it with no registration call at all.

Imperative escape hatch: register (or replace, by `id`) a route
contribution from an embedded/REPL caller. Extensions should prefer
the declarative `:gateway.slot/http-routes` channel-contribution slot
— the gateway pulls it with no registration call at all.
sourceraw docstring

gateway-release-session!clj

(gateway-release-session! sid)

Release a session VIEW when the owning channel exits: tell the daemon to stop the session's background resources (background shell children, REPLs) and drop its live runtime, then release the process-level client lease. This is NOT a per-session delete (the transcript stays resumable) and never sends daemon shutdown; the daemon stops itself only when refcount AND running-turn-count hit zero. Best-effort and never daemon-spawning — if no fresh daemon is registered there is nothing to release against.

Release a session VIEW when the owning channel exits: tell the daemon to
stop the session's background resources (background `shell` children, REPLs) and drop
its live runtime, then release the process-level client lease. This is NOT
a per-session delete (the transcript stays resumable) and never sends daemon
shutdown; the daemon stops itself only when refcount AND running-turn-count
hit zero. Best-effort and never daemon-spawning — if no fresh daemon is
registered there is nothing to release against.
sourceraw docstring

gateway-release-session-runtime!clj

(gateway-release-session-runtime! sid)

Release a session's live RUNTIME on the daemon WITHOUT touching the process client lease: stop its background resources (background shell children, managed REPLs) and drop its loop/env, keeping the transcript resumable. Used when ONE view of a session closes (e.g. a single TUI tab) while the owning process stays connected — so the whole-process refcount lease is left intact and the daemon is never nudged toward self-reap while other tabs remain open. Best-effort and never daemon-spawning — nothing to release against when no fresh daemon is registered.

Release a session's live RUNTIME on the daemon WITHOUT touching the process
client lease: stop its background resources (background `shell` children, managed REPLs)
and drop its loop/env, keeping the transcript resumable. Used when ONE view of
a session closes (e.g. a single TUI tab) while the owning process stays
connected — so the whole-process refcount lease is left intact and the daemon
is never nudged toward self-reap while other tabs remain open. Best-effort and
never daemon-spawning — nothing to release against when no fresh daemon is
registered.
sourceraw docstring

gateway-reorder-project-sessions!clj

(gateway-reorder-project-sessions! pid session-ids)

Persist a project's manual session order in one gateway call. Loose named sessions are adopted atomically; guests owned by another project are not moved.

Persist a project's manual session order in one gateway call. Loose named
sessions are adopted atomically; guests owned by another project are not moved.
sourceraw docstring

gateway-resource-logsclj

(gateway-resource-logs sid rid)

Captured output lines for a background via its daemon-side logs-fn, or nil.

Captured output lines for a background via its daemon-side logs-fn, or nil.
sourceraw docstring

gateway-router-diagnosticsclj

(gateway-router-diagnostics)

The WHOLE provider dialog in ONE gateway call.

GET /v1/router already carries every provider's status and limits, so a client that wants both for N providers reads it once instead of firing 2×N per-provider probes. Keyed by provider-id keyword: {:openai {:status {"is_authenticated" …} :limits {…}}}:status stays VERBATIM snake_case strings (same shape provider-status returns) and :limits is restored to the engine shape provider-limits returns, so both values drop straight into the callers those two functions already have.

The WHOLE provider dialog in ONE gateway call.

`GET /v1/router` already carries every provider's `status` and `limits`, so a
client that wants both for N providers reads it once instead of firing 2×N
per-provider probes. Keyed by provider-id keyword:
`{:openai {:status {"is_authenticated" …} :limits {…}}}` — `:status` stays
VERBATIM snake_case strings (same shape `provider-status` returns) and
`:limits` is restored to the engine shape `provider-limits` returns, so both
values drop straight into the callers those two functions already have.
sourceraw docstring

gateway-router-fleetclj

(gateway-router-fleet)

GET /v1/router — the unified router dialog payload assembled by the gateway: {"providers" [{"id" … "label" … "base_url" … "models" [...] "status" {"is_authenticated" …} "limits" {…}} …]}. Returned VERBATIM with snake_case STRING keys — NO keyword restoration. Consumers read the string keys directly ((get status "is_authenticated")).

GET /v1/router — the unified router dialog payload assembled by the gateway:
`{"providers" [{"id" … "label" … "base_url" … "models" [...]
"status" {"is_authenticated" …} "limits" {…}} …]}`. Returned VERBATIM with
snake_case STRING keys — NO keyword restoration. Consumers read the string
keys directly (`(get status "is_authenticated")`).
sourceraw docstring

gateway-running?clj

(gateway-running?)
source

gateway-search-session-idsclj

(gateway-search-session-ids query)

GET /v1/sessions/actions/search?q= — soul-id STRINGS whose transcript (user request + assistant text) matches query. Blank query → []. The heavy assistant text never crosses the wire; callers union these ids into a local title filter.

GET /v1/sessions/actions/search?q= — soul-id STRINGS whose transcript (user request +
assistant text) matches `query`. Blank query → []. The heavy assistant text
never crosses the wire; callers union these ids into a local title filter.
sourceraw docstring

gateway-search-session-matchesclj

(gateway-search-session-matches query)

GET /v1/sessions/actions/search?q= — like search-session-ids but each hit is TAGGED with WHERE it matched, RANKED by the server, and carries up to a handful of snippets: [{:id str :rank 0-3 :in-title? bool :in-request? bool :in-reply? bool :in-thinking? bool :request-snippet str :reply-snippet str :hits [{:side :request|:reply|:thinking :snippet str :at ms}]}]. :in-title? = the session's own name matched; :in-request? = the user's own request; :in-reply? = the assistant's answer; :in-thinking? = only its reasoning aside. The vector arrives in the gateway's own order — running sessions first, then FRESHEST first, the same order its session list is in — and is painted in it; :rank (0 best) says WHERE the query hit and a surface never re-orders. Blank query → []. Heavy assistant text never crosses the wire.

GET /v1/sessions/actions/search?q= — like `search-session-ids` but each hit is
TAGGED with WHERE it matched, RANKED by the server, and carries up to a handful
of snippets:
`[{:id str :rank 0-3 :in-title? bool :in-request? bool :in-reply? bool
   :in-thinking? bool :request-snippet str :reply-snippet str
   :hits [{:side :request|:reply|:thinking :snippet str :at ms}]}]`.
`:in-title?` = the session's own name matched; `:in-request?` = the user's own
request; `:in-reply?` = the assistant's answer; `:in-thinking?` = only its
reasoning aside. The vector arrives in the gateway's own order — running
sessions first, then FRESHEST first, the same order its session list is in —
and is painted in it; `:rank` (0 best) says WHERE the query hit and a surface
never re-orders. Blank query → []. Heavy assistant text never crosses the
wire.
sourceraw docstring

gateway-session-artifactsclj

(gateway-session-artifacts sid)

Every durable artifact sid has produced, string-keyed and in gateway order, or nil when the daemon cannot answer. nil is UNAVAILABLE — a channel must paint it differently from an index that is genuinely empty.

Every durable artifact `sid` has produced, string-keyed and in gateway order,
or nil when the daemon cannot answer. nil is UNAVAILABLE — a channel must
paint it differently from an index that is genuinely empty.
sourceraw docstring

gateway-session-modelclj

(gateway-session-model sid)
source

gateway-session-model-cachedclj

(gateway-session-model-cached sid)

Footer-frequency read of the session's model pref served from a per-sid cache that NEVER blocks the caller (issue #29, gateway leg: this used to be a live session-model HTTP round-trip per footer frame). A stale (or cold) entry kicks a background single-flight refresh and this returns the last-known value immediately (nil before the first success). set-session-model! writes through, so a pick made in THIS client shows on the very next frame.

Footer-frequency read of the session's model pref served from a per-sid
cache that NEVER blocks the caller (issue #29, gateway leg: this used to
be a live `session-model` HTTP round-trip per footer frame). A stale (or
cold) entry kicks a background single-flight refresh and this returns the
last-known value immediately (nil before the first success).
`set-session-model!` writes through, so a pick made in THIS client shows
on the very next frame.
sourceraw docstring

gateway-session-slashesclj

(gateway-session-slashes sid)
(gateway-session-slashes sid channel)

GET the gateway-owned slash catalog for sid and channel. The first call may initialize Python extensions in the gateway, so it uses the cold-load timeout.

GET the gateway-owned slash catalog for `sid` and `channel`. The first call may
initialize Python extensions in the gateway, so it uses the cold-load timeout.
sourceraw docstring

gateway-session-workspaceclj

(gateway-session-workspace sid)
source

gateway-set-router-default!clj

(gateway-set-router-default! provider-id model)

PATCH /v1/router — tag the PRIMARY provider/model pair (the router root every turn starts on). Returns {:provider-id … :model …}.

PATCH /v1/router — tag the PRIMARY provider/model pair (the router root every
turn starts on). Returns `{:provider-id … :model …}`.
sourceraw docstring

gateway-set-router-fallback!clj

(gateway-set-router-fallback!)
(gateway-set-router-fallback! provider-id model)

PATCH /v1/router — tag the FALLBACK provider/model pair: the router's second root, on a provider the primary does NOT use (the daemon refuses the primary's own with a 400). Zero args, or a nil provider, CLEARS the tag. Returns the resulting {:provider-id … :model …}, or nil once cleared.

PATCH /v1/router — tag the FALLBACK provider/model pair: the router's second
root, on a provider the primary does NOT use (the daemon refuses the primary's
own with a 400). Zero args, or a nil provider, CLEARS the tag. Returns the
resulting `{:provider-id … :model …}`, or nil once cleared.
sourceraw docstring

gateway-set-session-model!clj

(gateway-set-session-model! sid provider model)

PATCH the session's model pref in the daemon. Writes the returned pref straight through into the session-model-cached snapshot so the footer chip flips on the very next frame instead of waiting out the cache TTL.

PATCH the session's model pref in the daemon. Writes the returned pref
straight through into the `session-model-cached` snapshot so the footer
chip flips on the very next frame instead of waiting out the cache TTL.
sourceraw docstring

gateway-soulclj

(gateway-soul sid)
source

gateway-start!clj

(gateway-start!)
(gateway-start! {:keys [port host token-file require-token? db managed?]})

Start the gateway on the Jetty 12 core adapter with virtual threads. Returns {:port :host :token-file}. Throws when already running. Safe to call from any host process - the daemon (vis-agent gateway start), a TUI run, or an embedded caller.

Start the gateway on the Jetty 12 core adapter with virtual threads.
Returns `{:port :host :token-file}`. Throws when already running.
Safe to call from any host process - the daemon (`vis-agent gateway start`), a TUI
run, or an embedded caller.
sourceraw docstring

gateway-stop!clj

(gateway-stop!)

Stop the gateway server if running. Idempotent.

Stop the gateway server if running. Idempotent.
sourceraw docstring

gateway-stop-resource!clj

(gateway-stop-resource! sid rid)

Run the resource's stop-fn in the daemon and unregister it. Returns the daemon's stop result map ({:result "stopped"|"unknown"|… :id …}).

Run the resource's stop-fn in the daemon and unregister it. Returns the
daemon's stop result map (`{:result "stopped"|"unknown"|… :id …}`).
sourceraw docstring

gateway-submit-turn!clj

(gateway-submit-turn! sid opts)
source

gateway-submit-turn-sync!clj

(gateway-submit-turn-sync! sid {:keys [on-event] :as opts})
source

gateway-synthesize-speech!clj

(gateway-synthesize-speech! sid text {:keys [engine-id voice-id on-progress]})

Ask the gateway-owned speech engine to synthesize text and return a temporary WAV file owned by the caller. Progress is streamed for asynchronous jobs. A nil sid needs no conversation.

Ask the gateway-owned speech engine to synthesize `text` and return a temporary
WAV file owned by the caller. Progress is streamed for asynchronous jobs. A nil `sid` needs no conversation.
sourceraw docstring

gateway-toggle-setting!clj

(gateway-toggle-setting! id)

Atomically flip one boolean setting in the gateway and return its refreshed string-keyed settings row. The gateway owns both persistence and live runtime fan-out; clients must not mutate a process-local toggle registry instead.

Atomically flip one boolean setting in the gateway and return its refreshed
string-keyed settings row. The gateway owns both persistence and live runtime
fan-out; clients must not mutate a process-local toggle registry instead.
sourceraw docstring

gateway-transcribe-audio!clj

(gateway-transcribe-audio! sid audio-path {:keys [engine-id on-progress]})

Upload a WAV to the gateway-owned transcription engine, stream its progress, and return the transcript. audio-path is read by this client only; Sherpa and its model live solely in the gateway process. A nil sid needs no conversation.

Upload a WAV to the gateway-owned transcription engine, stream its progress,
and return the transcript. `audio-path` is read by this client only; Sherpa and
its model live solely in the gateway process. A nil `sid` needs no conversation.
sourceraw docstring

gateway-transcriptclj

(gateway-transcript sid)

Every turn of sid, hydrated. UNBOUNDED — the whole session is listed AND hydrated, which on a long session is seconds of work and megabytes of JSON. Prefer transcript-page for anything interactive.

Every turn of `sid`, hydrated. UNBOUNDED — the whole session is listed AND
hydrated, which on a long session is seconds of work and megabytes of JSON.
Prefer `transcript-page` for anything interactive.
sourceraw docstring

gateway-transcript-htmlclj

(gateway-transcript-html sid)

The gateway-rendered STANDALONE HTML transcript for sid — the canonical transcript->html, the HTML sibling of transcript-md. Returns the string, or nil on a non-2xx.

The gateway-rendered STANDALONE HTML transcript for `sid` — the canonical
`transcript->html`, the HTML sibling of `transcript-md`. Returns the string,
or nil on a non-2xx.
sourceraw docstring

gateway-transcript-mdclj

(gateway-transcript-md sid)

The gateway-rendered user/assistant dialog Markdown for sid — the canonical transcript->md :dialog. Returns the string, or nil on a non-2xx.

The gateway-rendered user/assistant dialog Markdown for `sid` — the canonical
`transcript->md :dialog`. Returns the string, or nil on a non-2xx.
sourceraw docstring

gateway-transcript-pageclj

(gateway-transcript-page sid {:keys [limit offset]})

A WINDOW of sid's transcript — the paging counterpart of transcript.

opts: :limit window size (nil = the whole transcript), :offset 0-based start in the OLDEST-FIRST list (nil = the NEWEST :limit turns). The gateway also caps a window in BYTES, so the reply's offset can come back HIGHER than the one asked for — page from the RETURNED offset, never from your own arithmetic.

Returns the canonical wire map {"turns" [...] "total" n "offset" n "has_more" bool} (oldest-first turns).

A WINDOW of `sid`'s transcript — the paging counterpart of `transcript`.

`opts`: `:limit` window size (nil = the whole transcript), `:offset` 0-based
start in the OLDEST-FIRST list (nil = the NEWEST `:limit` turns). The gateway
also caps a window in BYTES, so the reply's `offset` can come back HIGHER
than the one asked for — page from the RETURNED `offset`, never from your own
arithmetic.

Returns the canonical wire map `{"turns" [...] "total" n "offset" n
"has_more" bool}` (oldest-first turns).
sourceraw docstring

gateway-turn-traceclj

(gateway-turn-trace sid tid)

Canonical wire iterations of ONE persisted turn (nil when the id is unknown to the daemon).

Canonical wire iterations of ONE persisted turn (nil when the id is
unknown to the daemon).
sourceraw docstring

gateway-unregister-contributed-sse!clj

(gateway-unregister-contributed-sse! stream-id)

Remove a contributed SSE connection and re-run managed-idle shutdown policy.

Remove a contributed SSE connection and re-run managed-idle shutdown policy.
sourceraw docstring

gateway-update-project!clj

(gateway-update-project! pid opts)
source

gateway-update-queued-turn!clj

(gateway-update-queued-turn! sid tid request)
source

gateway-view-action!clj

(gateway-view-action! sid view-id action)

Apply one operator action to the DAEMON-side View view-id of sid.

action is the closed View map: {:action :submit :values …}, {:action :cancel}, {:action :select :node-id … :item-ids …}, or {:action :interrupt :note …}. Kind is resolved by the daemon from the View, never encoded into this route. Returns the engine's canonical action outcome.

Apply one operator action to the DAEMON-side View `view-id` of `sid`.

`action` is the closed View map: `{:action :submit :values …}`,
`{:action :cancel}`, `{:action :select :node-id … :item-ids …}`, or
`{:action :interrupt :note …}`. Kind is resolved by the daemon from the View,
never encoded into this route. Returns the engine's canonical action outcome.
sourceraw docstring

get-localsclj

(get-locals _environment)

User-defined sandbox vars surface. Live-vars introspection is cosmetic-off for the Python engine (the agent uses its own Python scope + stdlib), so this returns an empty map. Kept as a stable seam for the trailer/renderer callers.

User-defined sandbox vars surface. Live-vars introspection is cosmetic-off
for the Python engine (the agent uses its own Python scope + stdlib), so this
returns an empty map. Kept as a stable seam for the trailer/renderer callers.
sourceraw docstring

get-resourceclj

(get-resource session id)

DATA map for session+id, or nil.

DATA map for `session`+`id`, or nil.
sourceraw docstring

get-routerclj

(get-router)

Get or create the shared LLM router.

Honors :router opts from ~/.vis/config.edn (:rate-limit, :network, :budget, ...). Without that block svar's built-in defaults apply. See config/router-opts for the supported keys.

Get or create the shared LLM router.

Honors `:router` opts from `~/.vis/config.edn` (`:rate-limit`,
`:network`, `:budget`, ...). Without that block svar's built-in
defaults apply. See `config/router-opts` for the supported keys.
sourceraw docstring

has-provider?clj

(has-provider? provider-id)
source

humanize-fact-keyclj

(humanize-fact-key k)

Human-facing label for a fact/entity key. A turn_<N> key reads as Turn <N> for DISPLAY. Every other key is shown with underscores/hyphens normalized to SPACES and the first letter capitalized (api_key -> Api key, clj_eval_render -> Clj eval render). DISPLAY ONLY — the stored key stays verbatim, so restore still matches. Canonical across the context panel and every channel (TUI, web).

Fact/entity keys are model-authored strings (strings-only boundary), so (str k) is total here — no keyword branch.

Human-facing label for a fact/entity key. A `turn_<N>` key reads as
`Turn <N>` for DISPLAY. Every other key is shown with
underscores/hyphens normalized to SPACES and the first letter capitalized
(`api_key` -> `Api key`, `clj_eval_render` -> `Clj eval render`).
DISPLAY ONLY — the stored key stays verbatim, so restore still
matches. Canonical across the context panel and every channel (TUI, web).

Fact/entity keys are model-authored strings (strings-only boundary),
so `(str k)` is total here — no keyword branch.
sourceraw docstring

init!clj

(init!)

Redirect System/out and System/err to the log file. Lanterna uses tty-in / tty-out for terminal I/O. Call from the TUI entry point.

Redirect System/out and System/err to the log file. Lanterna uses
tty-in / tty-out for terminal I/O. Call from the TUI entry point.
sourceraw docstring

init-cli!clj

(init-cli!)

Logging init for non-TUI processes. Same redirects as init! but without the shutdown hook (CLI commands run to completion and exit).

Logging init for non-TUI processes. Same redirects as init! but
without the shutdown hook (CLI commands run to completion and exit).
sourceraw docstring

install-extension!clj

(install-extension! environment ext)

Register a validated extension into environment (per-env registration, distinct from the global-registry register-extension! defined earlier in this file).

If an extension with the same :ext/name is already registered, it is replaced (not duplicated). Enables hot-swap via reload-extension! (removed for GraalVM native-image compatibility).

Returns environment for chaining.

Register a validated extension into `environment` (per-env registration,
distinct from the global-registry `register-extension!` defined earlier
in this file).

If an extension with the same `:ext/name` is already registered,
it is replaced (not duplicated). Enables hot-swap via
`reload-extension!` (removed for GraalVM native-image compatibility).

Returns `environment` for chaining.
sourceraw docstring

limits-compact-cellsclj

(limits-compact-cells rows)

Compact a group of rows into {:prefix <shared plan name or nil> :cells [{:row <row> :text "5h 100%"}]}.

When every row's label ends in a window suffix and they all carry the SAME plan name, that name is hoisted OUT of the cells into :prefix, so a three-window plan reads "OpenCode Go 5h 100% · 7d 100% · 30d 99%" instead of spelling "OpenCode Go" three times and "left" three times. Otherwise :prefix is nil and each cell keeps its own label.

Channels render the pieces themselves (the TUI footer joins with / and stamps a reset on one cell) but never re-derive them.

Compact a group of rows into
`{:prefix <shared plan name or nil> :cells [{:row <row> :text "5h 100%"}]}`.

When every row's label ends in a window suffix and they all carry the SAME
plan name, that name is hoisted OUT of the cells into `:prefix`, so a
three-window plan reads "OpenCode Go 5h 100% · 7d 100% · 30d 99%" instead
of spelling "OpenCode Go" three times and "left" three times. Otherwise
`:prefix` is nil and each cell keeps its own label.

Channels render the pieces themselves (the TUI footer joins with ` / ` and
stamps a reset on one cell) but never re-derive them.
sourceraw docstring

limits-dynamic-summaryclj

(limits-dynamic-summary limits)
(limits-dynamic-summary limits max-rows)

Compact one-line summary of the most informative :dynamic :limits rows for a provider's normalized limits report.

Picks rows with signal first, falls back to all rows when nothing has signal yet (so a fresh, all-zero report still surfaces SOMETHING rather than collapsing to empty). Takes up to max-rows (default 3 — the widest plan family shipped is 5h + 7d + 30d), compacts them through compact-limit-cells so the plan name is written once, and joins the cells with ·:

OpenCode Go 5h 100% · 7d 100% · 30d 99%

Returns nil when there's nothing to render.

Compact one-line summary of the most informative `:dynamic :limits`
rows for a provider's normalized limits report.

Picks rows with signal first, falls back to all rows when nothing
has signal yet (so a fresh, all-zero report still surfaces SOMETHING
rather than collapsing to empty). Takes up to `max-rows` (default 3 — the
widest plan family shipped is 5h + 7d + 30d), compacts them through
`compact-limit-cells` so the plan name is written once, and joins the cells
with ` · `:

  OpenCode Go 5h 100% · 7d 100% · 30d 99%

Returns nil when there's nothing to render.
sourceraw docstring

limits-format-numberclj

(limits-format-number n)

Render a numeric usage/limit/remaining value with a single-decimal suffix when the value is non-integral, else as a clean integer. Locale/ROOT keeps the JVM locale from injecting a comma decimal separator next to English suffix text.

Render a numeric usage/limit/remaining value with a single-decimal
suffix when the value is non-integral, else as a clean integer.
`Locale/ROOT` keeps the JVM locale from injecting a comma decimal
separator next to English suffix text.
sourceraw docstring

limits-format-usageclj

(limits-format-usage {:keys [used limit remaining is-unlimited] :as row})

Render the usage/remaining portion of a row as a short string, choosing the most informative shape the row's numbers allow:

  • explicit is-unlimited flag -> "unlimited"
  • percentage-style row -> "47% left"
  • used + limit + remaining -> "3/5 used (2 left)"
  • used + limit -> "3/5 used"
  • remaining + limit -> "2/5 left"
  • remaining only -> "2 left"
  • used only -> "3 used"
  • none of the above -> nil

Returns nil only when the row carries no usage signal at all, so callers can (when usage ...) to skip empty cells.

Render the usage/remaining portion of a row as a short string,
choosing the most informative shape the row's numbers allow:

  - explicit `is-unlimited` flag         -> "unlimited"
  - percentage-style row               -> "47% left"
  - used + limit + remaining           -> "3/5 used (2 left)"
  - used + limit                       -> "3/5 used"
  - remaining + limit                  -> "2/5 left"
  - remaining only                     -> "2 left"
  - used only                          -> "3 used"
  - none of the above                  -> nil

Returns nil only when the row carries no usage signal at all, so
callers can `(when usage ...)` to skip empty cells.
sourceraw docstring

limits-generic-labelclj

(limits-generic-label row)

Human label for a dynamic-limit row. Hand-rolled overrides for the widely-known plan rows; fallback derives a label from :label or :id, trimming the redundant Quota / Quota (%) suffixes the raw provider rows ship with. :id is coerced via ->kw so the overrides match whether the report came in-process (keyword ids) or across the gateway wire (string ids).

Human label for a dynamic-limit row. Hand-rolled overrides for the
widely-known plan rows; fallback derives a label from `:label` or
`:id`, trimming the redundant ` Quota` / ` Quota (%)` suffixes the
raw provider rows ship with. `:id` is coerced via `->kw` so the
overrides match whether the report came in-process (keyword ids) or
across the gateway wire (string ids).
sourceraw docstring

limits-label+usageclj

(limits-label+usage row)

Compact cell for a SINGLE row — its own short label plus its compact usage ("Codex 5h 47%"), or the label alone when the row carries no usage signal. generic-limit-label bottoms out at "Limit", so a row always renders.

Compact cell for a SINGLE row — its own short label plus its compact usage
("Codex 5h 47%"), or the label alone when the row carries no usage signal.
`generic-limit-label` bottoms out at "Limit", so a row always renders.
sourceraw docstring

limits-percentage-row?clj

(limits-percentage-row? {:keys [id kind limit remaining]})

True when the row is best displayed as a percent-remaining (the provider reports a 0-100 percentage rather than raw token counts). The ID allowlist covers the Codex / Z.ai plan windows; the :rate + :limit 100 heuristic catches generic percentage rows (the Anthropic Claude windows). id/kind are coerced via ->kw so a report that crossed the gateway wire (string values) matches the same as an in-process one (keyword values).

True when the row is best displayed as a percent-remaining (the
provider reports a 0-100 percentage rather than raw token counts).
The ID allowlist covers the Codex / Z.ai plan windows; the
`:rate` + `:limit 100` heuristic catches generic percentage rows
(the Anthropic Claude windows). `id`/`kind` are coerced via `->kw`
so a report that crossed the gateway wire (string values) matches
the same as an in-process one (keyword values).
sourceraw docstring

limits-prioritize-rowsclj

(limits-prioritize-rows rows)

Stable reorder of limit rows: rolling plan windows first, SHORTEST window leading (5h before 7d, never the other way round because the weekly bucket happens to be tighter today), then everything else by limit-row-pressure so whatever is blocking leads any truncated rendering.

Stable reorder of limit rows: rolling plan windows first, SHORTEST window
leading (5h before 7d, never the other way round because the weekly bucket
happens to be tighter today), then everything else by `limit-row-pressure`
so whatever is blocking leads any truncated rendering.
sourceraw docstring

limits-row-exhausted?clj

(limits-row-exhausted? {:keys [is-unlimited remaining limit used]})

True when a metered row has nothing left: not unlimited, a numeric :remaining at (or below) zero, and enough context to know that the zero is a WALL — either a positive :limit or positive :used.

A brand new all-zero row ({:remaining 0 :limit 0}) is NOT exhausted; it simply has not been filled in yet.

True when a metered row has nothing left: not unlimited, a numeric
`:remaining` at (or below) zero, and enough context to know that the
zero is a WALL — either a positive `:limit` or positive `:used`.

A brand new all-zero row (`{:remaining 0 :limit 0}`) is NOT exhausted;
it simply has not been filled in yet.
sourceraw docstring

limits-row-has-signal?clj

(limits-row-has-signal? row)

True when the row has usage or reset signal worth surfacing. Used to prefer informative rows when the visible area is tight. A reset timestamp is signal even when the provider reports zero remaining and omits a limit: that's exactly when the user needs to know when credits come back.

True when the row has usage or reset signal worth surfacing. Used to
prefer informative rows when the visible area is tight. A reset timestamp
is signal even when the provider reports zero remaining and omits a limit:
that's exactly when the user needs to know when credits come back.
sourceraw docstring

limits-row-pressureclj

(limits-row-pressure {:keys [is-unlimited remaining limit] :as row})

Sort key ranking a row by how much it constrains the user RIGHT NOW:

  1. exhausted metered rows (0 left, requests are being rejected)
  2. metered rows, tightest remaining fraction first
  3. rows with no tank at all (:is-unlimited)

Without this, a provider that reports its unlimited buckets first (GitHub Copilot lists chat, completions, then premium_interactions) summarises as "Chat unlimited · Completions unlimited" while the ONE bucket that actually rejects requests sits silently at 0 remaining.

Sort key ranking a row by how much it constrains the user RIGHT NOW:

  0. exhausted metered rows (0 left, requests are being rejected)
  1. metered rows, tightest remaining fraction first
  2. rows with no tank at all (`:is-unlimited`)

Without this, a provider that reports its unlimited buckets first
(GitHub Copilot lists `chat`, `completions`, then `premium_interactions`)
summarises as "Chat unlimited · Completions unlimited" while the ONE
bucket that actually rejects requests sits silently at 0 remaining.
sourceraw docstring

list-resourcesclj

(list-resources session)

Vector of live resource DATA maps for session, dead ones pruned and every health-capable status refreshed first (parallel, hard-timeout probes). This is what the footer renders and what repl_status answers from — ONLY the calling session's resources. Nothing about a resource rides in ctx.

Vector of live resource DATA maps for `session`, dead ones pruned and every
health-capable `status` refreshed first (parallel, hard-timeout probes).
This is what the footer renders and what `repl_status` answers from — ONLY
the calling session's resources. Nothing about a resource rides in ctx.
sourceraw docstring

live-viewclj

source

live-viewsclj

source

llm-text!clj

(llm-text! {:keys [messages system prompt reasoning temperature routing]
            :as opts})

Fast helper LLM call for extensions.

Uses svar routing (:routing {:optimize :cost}) instead of Vis-side model name heuristics. The call still goes through svar/ask-code! because Vis no longer uses the retired ask! structured-output path; :lang "text", :reasoning :off, and :code-tail-pointer? true make the return a plain text string under :text. Callers may pass either :messages or :system + :prompt.

Fast helper LLM call for extensions.

Uses svar routing (`:routing {:optimize :cost}`) instead of Vis-side model
name heuristics. The call still goes through `svar/ask-code!` because Vis no
longer uses the retired `ask!` structured-output path; `:lang "text"`,
`:reasoning :off`, and `:code-tail-pointer? true` make the return a plain
text string under :text. Callers may pass either :messages or :system +
:prompt.
sourceraw docstring

load-configclj

(load-config)
(load-config require-providers?)

Load the validated YAML config and adapt its finite schema keys to internal keyword-keyed domain maps. load-config-raw retains the original string keys.

This is also the ${NAME} interpolation boundary. It is done HERE and not in load-config-raw on purpose: the raw loaders are the read half of every read-modify-write into ~/.vis/state.yml, so resolving there would write the plaintext secret straight back to disk. save-config! runs restore-env-refs as the matching guard for values that still reach a write through this keywordized view. Pass false for require-providers? when the caller resolves runtime-only providers separately; preserve its settings even without a persisted provider fleet.

Load the validated YAML config and adapt its finite schema keys to internal
keyword-keyed domain maps. `load-config-raw` retains the original string keys.

This is also the `${NAME}` interpolation boundary. It is done HERE and not in
`load-config-raw` on purpose: the raw loaders are the read half of every
read-modify-write into `~/.vis/state.yml`, so resolving there would write the
plaintext secret straight back to disk. `save-config!` runs
`restore-env-refs` as the matching guard for values that still reach a write
through this keywordized view. Pass false for `require-providers?` when the
caller resolves runtime-only providers separately; preserve its settings even
without a persisted provider fleet.
sourceraw docstring

load-config-rawclj

(load-config-raw)

Load raw config as the deep-merge of four YAML sources — later sources win, nested maps merge, scalar/vector values replace:

  1. ~/.vis/config.yml (or .yaml / vis.yml / vis.yaml) — hand-written global base
  2. ~/.vis/state.yml — machine-written global store (OAuth tokens, TUI-added providers); wins over the hand-written base
  3. <workspace>/vis.yml (or vis.yaml) — visible project root, the committed team config
  4. <workspace>/.vis/config.yml (or .yaml) — hidden project overlay; the nested overlay wins over the root file (personal beats committed)

Project tiers follow workspace/cwd, bound to the session's workspace, not the gateway launch directory. Unbound CLI/bootstrap callers use invocation cwd. Memoized against source paths and their mtime+size (see config-raw-cache).

Load raw config as the deep-merge of four YAML sources — later sources win,
nested maps merge, scalar/vector values replace:

1. `~/.vis/config.yml` (or `.yaml` / `vis.yml` / `vis.yaml`) — hand-written
   global base
2. `~/.vis/state.yml` — machine-written global store (OAuth tokens, TUI-added
   providers); wins over the hand-written base
3. `<workspace>/vis.yml` (or `vis.yaml`) — visible project root, the committed
   team config
4. `<workspace>/.vis/config.yml` (or `.yaml`) — hidden project overlay; the
   nested overlay wins over the root file (personal beats committed)

Project tiers follow `workspace/cwd`, bound to the session's workspace, not
the gateway launch directory. Unbound CLI/bootstrap callers use invocation cwd.
Memoized against source paths and their mtime+size (see `config-raw-cache`).
sourceraw docstring

load-python-extensions!clj

(load-python-extensions!)
(load-python-extensions! {:keys [dirs sync-projects?]})

Scan the Python extension dirs (default: ~/.vis/extensions and <cwd>/.vis/extensions) and (re)load every *.py file. Idempotent: when no file changed since the last scan this is a cheap no-op. On any change the whole set is torn down and rebuilt (contexts are ~40ms warm on the shared engine) — deterministic ordering, no partial states.

Change is measured over each extension's WHOLE import root, never its entry file alone — a package module the entry imports is part of the extension — and every root is FROZEN at load (freeze-root!), one freeze per root per pass.

A file that fails to load is recorded in load-failures (and surfaced by vis-agent doctor) — it never crashes the host.

Returns {:loaded n :failed n :changed? bool}.

Scan the Python extension dirs (default: `~/.vis/extensions` and
`<cwd>/.vis/extensions`) and (re)load every `*.py` file. Idempotent:
when no file changed since the last scan this is a cheap no-op. On any
change the whole set is torn down and rebuilt (contexts are ~40ms warm
on the shared engine) — deterministic ordering, no partial states.

Change is measured over each extension's WHOLE import root, never its entry
file alone — a package module the entry imports is part of the extension —
and every root is FROZEN at load (`freeze-root!`), one freeze per root per
pass.

A file that fails to load is recorded in `load-failures` (and surfaced
by `vis-agent doctor`) — it never crashes the host.

Returns `{:loaded n :failed n :changed? bool}`.
sourceraw docstring

loaded-python-extensionsclj

(loaded-python-extensions)

Snapshot of the currently loaded Python extensions: {<canonical-path> {:sha ... :ext-name ...}} (context handle elided).

Snapshot of the currently loaded Python extensions:
`{<canonical-path> {:sha ... :ext-name ...}} ` (context handle elided).
sourceraw docstring

make-progress-trackerclj

(make-progress-tracker)
(make-progress-tracker {:keys [on-update]})

Create a phased progress tracker.

Returns {:on-chunk fn :get-timeline fn}. The :on-chunk fn accepts the loop's phased chunks and returns nil. The :get-timeline fn returns the accumulated timeline vec (oldest-iteration first).

on-update (when supplied) is called (on-update timeline chunk) after every chunk update, so the consumer can re-render incrementally.

Create a phased progress tracker.

Returns `{:on-chunk fn :get-timeline fn}`. The `:on-chunk` fn
accepts the loop's phased chunks and returns nil. The
`:get-timeline` fn returns the accumulated timeline vec
(oldest-iteration first).

`on-update` (when supplied) is called `(on-update timeline chunk)`
after every chunk update, so the consumer can re-render
incrementally.
sourceraw docstring

manifest-initializersclj

(manifest-initializers)

The qualified symbol of every initializer, in manifest order.

The qualified symbol of every initializer, in manifest order.
sourceraw docstring

markdown->astclj

(markdown->ast text)
(markdown->ast text {:keys [soft-break]})

Parse a Markdown string into canonical transient Markdown tree. Idempotent: when the input is already canonical IR, returns it unchanged (identical? preserved — cache-friendly).

This is the SINGLE entry point for turning Markdown source into IR. Used by:

  • the final-answer pipeline (model's plain-prose Markdown answer)
  • thinking text from the model
  • user-typed messages from the TUI input box

Returns canonical [:ast & blocks] directly (no further ->ast round-trip needed). Empty / nil input yields [:ast {}].

Implementation: commonmark-java parser + GFM tables / strikethrough extensions, then a faithful Node→IR walker. Soft line breaks collapse to a single space; hard line breaks become [:br].

opts (2-arity) currently understands {:soft-break :hard}, which lifts every bare newline to [:br] instead of a space — used for line-oriented user/pasted input so the rendered bubble keeps the exact line structure the user typed. Default keeps prose semantics.

Parse a Markdown string into canonical transient Markdown tree.
Idempotent: when the input is already canonical IR, returns it
unchanged (`identical?` preserved — cache-friendly).

This is the SINGLE entry point for turning Markdown source into IR.
Used by:
  - the final-answer pipeline (model's plain-prose Markdown answer)
  - thinking text from the model
  - user-typed messages from the TUI input box

Returns canonical `[:ast & blocks]` directly (no further `->ast`
round-trip needed). Empty / nil input yields `[:ast {}]`.

Implementation: commonmark-java parser + GFM tables / strikethrough
extensions, then a faithful Node→IR walker. Soft line breaks collapse
to a single space; hard line breaks become `[:br]`.

`opts` (2-arity) currently understands `{:soft-break :hard}`, which
lifts every bare newline to `[:br]` instead of a space — used for
line-oriented user/pasted input so the rendered bubble keeps the
exact line structure the user typed. Default keeps prose semantics.
sourceraw docstring

meta-costclj

(meta-cost cost)

Humanized dollar cost — "~$0.0070" / "~$1.23". nil for zero / missing. Extra decimals for sub-cent turns so they don't round down to "$0".

Humanized dollar cost — "~$0.0070" / "~$1.23". nil for zero / missing.
Extra decimals for sub-cent turns so they don't round down to "$0".
sourceraw docstring

meta-fallback-noteclj

(meta-fallback-note {:keys [llm-selected llm-fallback? llm-routing-trace]})

Faint routing note when a turn fell back or retried a provider: ↳ from <selected-model> — <reason>, retried N×, prompt cache lost, session now on <model> reason prefers the HTTP status (429) on a fallback event, then the reason keyword, then the free-form error. Retry-only traces use their final retry event, so a provider failure is never rendered as merely retried N×.

A :scope :session-pick event means the rescue also MOVED the session's pick, so the model chip in every surface now names a provider the human never chose: the note is the one line that says why it changed (issue #154). It is never the anchor for from, which stays this turn's own route.

A route that CHANGED provider or model also lost prompt-cache continuity: the peer never saw the cache the pinned route built, so every following request re-sends the whole context. That silent 4× cost step is the reported half of issue #154 the numbers never showed, so the note says it in words on the turn it happens.

A :llm.routing/model-fallback moved the MODEL inside one provider — Anthropic's safety classifier declining this request is the switch Vis raises that way. Nothing about the credential or the provider failed, so it reads as its own reason and never as a retry, but the cache is gone all the same: an Anthropic cache belongs to ONE model. Returns nil when the trace has neither a fallback nor retries. Shared so the TUI can float it on its own faint row while the CLI folds it inline.

Faint routing note when a turn fell back or retried a provider:
  ↳ from <selected-model> — <reason>, retried N×, prompt cache lost, session now on <model>
`reason` prefers the HTTP status (429) on a fallback event, then the reason
keyword, then the free-form error. Retry-only traces use their final retry
event, so a provider failure is never rendered as merely `retried N×`.

A `:scope :session-pick` event means the rescue also MOVED the session's pick, so
the model chip in every surface now names a provider the human never chose: the
note is the one line that says why it changed (issue #154). It is never the
anchor for `from`, which stays this turn's own route.

A route that CHANGED provider or model also lost prompt-cache continuity: the peer
never saw the cache the pinned route built, so every following request re-sends the
whole context. That silent 4× cost step is the reported half of issue #154 the
numbers never showed, so the note says it in words on the turn it happens.

A `:llm.routing/model-fallback` moved the MODEL inside one provider — Anthropic's
safety classifier declining this request is the switch Vis raises that way. Nothing
about the credential or the provider failed, so it reads as its own reason and never
as a retry, but the cache is gone all the same: an Anthropic cache belongs to ONE
model.
Returns nil when the trace has neither a fallback nor retries. Shared so the
TUI can float it on its own faint row while the CLI folds it inline.
sourceraw docstring

meta-summary-lineclj

(meta-summary-line result)
(meta-summary-line {:keys [tokens cost duration-ms] :as result}
                   {:keys [model prefix suffix]})

The canonical, humanized turn-summary MAIN line, shared verbatim by the CLI bracket and the TUI bubble footer:

<provider/model> · <in→out (cached)> · ~$cost · <duration>

Zero-usage and zero-cost slots are dropped (no "0→0", no "$0"), so a turn that produced nothing reads as just the model + time. Does NOT include the fallback note — that is meta-fallback-note, which single-line surfaces fold in via format-meta-line and the TUI floats on a second row.

opts keeps the legacy override hooks: {:model <string|false> :prefix [...] :suffix [...]}:model false suppresses the model slot, a string overrides it; prefix/suffix are extra slots spliced in around the standard ones.

The canonical, humanized turn-summary MAIN line, shared verbatim by the CLI
bracket and the TUI bubble footer:

  <provider/model>  ·  <in→out (cached)>  ·  ~$cost  ·  <duration>

Zero-usage and zero-cost slots are dropped (no "0→0", no "$0"), so a turn
that produced nothing reads as just the model + time. Does NOT include the
fallback note — that is `meta-fallback-note`, which single-line surfaces fold
in via `format-meta-line` and the TUI floats on a second row.

`opts` keeps the legacy override hooks: `{:model <string|false> :prefix [...]
:suffix [...]}` — `:model false` suppresses the model slot, a string overrides
it; prefix/suffix are extra slots spliced in around the standard ones.
sourceraw docstring

meta-tokensclj

(meta-tokens tokens)

Humanized token slot — "11.5k→35", with " (cached 4.1k)" only when the cached-input count is positive. Returns nil for a ZERO-usage turn (no input AND no output) so a failed / empty provider call never renders a bare "0→0".

Humanized token slot — "11.5k→35", with " (cached 4.1k)" only when the
cached-input count is positive. Returns nil for a ZERO-usage turn (no input
AND no output) so a failed / empty provider call never renders a bare
"0→0".
sourceraw docstring

model-nameclj

(model-name model)

Extract the model name string from a model (string or {:name str}).

Extract the model name string from a model (string or `{:name str}`).
sourceraw docstring

model-pricingclj

(model-pricing model)

Per-model price table entry (USD per MILLION tokens) for model, looked up by exact model name in svar's MODEL_PRICING{:input :output :cache-read :cached-input …} — or nil when the model isn't priced. Read-only view over the same table estimate-token-cost bills against, so channel pickers show the price that actually gets charged.

Per-model price table entry (USD per MILLION tokens) for `model`, looked up
by exact model name in svar's `MODEL_PRICING` — `{:input :output :cache-read
:cached-input …}` — or nil when the model isn't priced. Read-only view over
the same table `estimate-token-cost` bills against, so channel pickers show
the price that actually gets charged.
sourceraw docstring

model-routing-statusclj

(model-routing-status displayed-provider displayed-model)
(model-routing-status router displayed-provider displayed-model)

Live routing health for the model a channel is DISPLAYING (displayed-provider

  • displayed-model — the per-session pick or the config default the picker shows).

svar opens a circuit breaker on a provider after repeated transient failures (5xx / 'Overloaded' 529 / dropped streams) and routes turns to the next AVAILABLE provider so work keeps flowing. The displayed model is computed from config ORDER and is NOT breaker-aware, so during an outage the picker says opus while turns actually land on zai. This reconciles the two: when the displayed provider's breaker is open/half-open, it reports what svar is actually serving so the channel can surface ⚠ <displayed> overloaded — routing to <serving>.

Returns nil when the displayed provider is healthy, else {:overloaded-provider <kw> :overloaded-model <str> :serving-provider <kw> :serving-model <str>}. serving-* is nil if every provider is down.

Live routing health for the model a channel is DISPLAYING (`displayed-provider`
+ `displayed-model` — the per-session pick or the config default the picker
shows).

svar opens a circuit breaker on a provider after repeated transient failures
(5xx / 'Overloaded' 529 / dropped streams) and routes turns to the next
AVAILABLE provider so work keeps flowing. The displayed model is computed
from config ORDER and is NOT breaker-aware, so during an outage the picker
says `opus` while turns actually land on `zai`. This reconciles the two: when
the displayed provider's breaker is open/half-open, it reports what svar is
actually serving so the channel can surface
`⚠ <displayed> overloaded — routing to <serving>`.

Returns nil when the displayed provider is healthy, else
`{:overloaded-provider <kw> :overloaded-model <str>
  :serving-provider <kw> :serving-model <str>}`. `serving-*` is nil if every
provider is down.
sourceraw docstring

new-idclj

(new-id)
source

new-uuidclj

(new-uuid)
source

non-blankclj

(non-blank x)

x trimmed to a string, or nil when it is nil, empty or all whitespace.

`x` trimmed to a string, or nil when it is nil, empty or all whitespace.
sourceraw docstring

normalize-reasoningclj

(normalize-reasoning text)

Canonical normalization for model reasoning / thinking text before it is rendered as a trace. Reasoning streams carry whitespace-padded blank rows (trailing spaces/tabs the model emits) and paragraph-style double newlines that make the compact thinking block look ragged (glm-5.2 especially). Strip per-line trailing whitespace, collapse every run of newlines down to ONE line break, then give the trace BREATHING ROOM: a line that ENDS A SENTENCE (./!/?/, optionally closed by a quote/paren/bracket) and is followed by more text gets a blank line after it, so consecutive sentences read as separate paragraphs instead of a wall. Finally trim. Shared by every channel so the TUI bubble and the web thinking card normalize identically.

Canonical normalization for model reasoning / thinking text before it is
rendered as a trace. Reasoning streams carry whitespace-padded blank rows
(trailing spaces/tabs the model emits) and paragraph-style double newlines
that make the compact thinking block look ragged (glm-5.2 especially). Strip
per-line trailing whitespace, collapse every run of newlines down to ONE line
break, then give the trace BREATHING ROOM: a line that ENDS A SENTENCE
(`.`/`!`/`?`/`…`, optionally closed by a quote/paren/bracket) and is
followed by more text gets a blank line after it, so consecutive sentences
read as separate paragraphs instead of a wall. Finally trim. Shared by every
channel so the TUI bubble and the web thinking card normalize identically.
sourceraw docstring

normalize-statusclj

(normalize-status status)

Map runtime status keywords to the schema CHECK constraint values. Allowed: running, done, error, interrupted.

Map runtime status keywords to the schema CHECK constraint values.
Allowed: running, done, error, interrupted.
sourceraw docstring

notificationsclj

(notifications)

Vec of currently-active notifications, oldest first. Implicitly prunes expired entries before returning so a paint loop reading this never has to re-check :until deadlines.

Vec of currently-active notifications, oldest first. Implicitly
prunes expired entries before returning so a paint loop reading
this never has to re-check `:until` deadlines.
sourceraw docstring

notify!clj

(notify! text & {:keys [level ttl-ms] :or {level :info ttl-ms DEFAULT_TTL_MS}})

Push a new notification. Returns the entry's id (uuid string) so the caller can later dismiss! it manually.

Options: :level one of #{:info :success :warn :error} - default :info. Channels use the level for visual treatment (color, emoji prefix, etc.). :ttl-ms lifespan in ms. Default 3000. nil = sticky / no auto expiry; the notification stays until dismiss!d.

The notification is appended to the in-memory vec and every registered watcher is fired with the new full vec.

Push a new notification. Returns the entry's id (uuid string) so
the caller can later `dismiss!` it manually.

Options:
  :level   one of #{:info :success :warn :error} - default :info.
           Channels use the level for visual treatment (color,
           emoji prefix, etc.).
  :ttl-ms  lifespan in ms. Default 3000. nil = sticky / no auto
           expiry; the notification stays until `dismiss!`d.

The notification is appended to the in-memory vec and every
registered watcher is fired with the new full vec.
sourceraw docstring

now-msclj

(now-ms)

Milliseconds since the epoch — the engine's one wall clock.

Milliseconds since the epoch — the engine's one wall clock.
sourceraw docstring

on-cancel!clj

(on-cancel! token thunk)

Register a no-arg thunk to fire the moment cancel! is invoked on token. Returns a dispose! thunk the caller MUST invoke when the cancellable work finishes normally — otherwise callbacks accumulate for the token's lifetime.

If cancel! has already fired on this token, thunk runs synchronously here and dispose! is a no-op. This matches the contract every consumer wants: registering AFTER cancellation must still cancel, not silently swallow the request.

Replaces the atom-watch pattern earlier eval boundaries hand-rolled: one shared callback list, no per-consumer add-watch / remove-watch plumbing, no risk of leaving a watch on the flag after the worker finishes.

Register a no-arg `thunk` to fire the moment `cancel!` is invoked
on `token`. Returns a `dispose!` thunk the caller MUST invoke when
the cancellable work finishes normally — otherwise callbacks
accumulate for the token's lifetime.

If `cancel!` has already fired on this token, `thunk` runs
synchronously here and `dispose!` is a no-op. This matches the
contract every consumer wants: registering AFTER cancellation
must still cancel, not silently swallow the request.

Replaces the atom-watch pattern earlier eval boundaries hand-rolled:
one shared callback list, no per-consumer add-watch / remove-watch
plumbing, no risk of leaving a watch on the flag after the worker
finishes.
sourceraw docstring

op-presentationclj

(op-presentation op)

Engine-owned presentation metadata for a tool's :op keyword: {:tag ...}. Tool wrappers merge this into their :info/:metadata so channels read canonical keys.

Badge LABEL is derived from :tag by the channel, not stored here. Color / glyph / layout remain pure channel concerns.

Engine-owned presentation metadata for a tool's `:op` keyword:
`{:tag ...}`. Tool wrappers merge this into their `:info`/`:metadata`
so channels read canonical keys.

Badge LABEL is derived from `:tag` by the channel, not stored here.
Color / glyph / layout remain pure channel concerns.
sourceraw docstring

op-tagclj

(op-tag op-keyword)

Return the :observation | :mutation tag for op-keyword. Unknown ops fail closed; every symbol must declare :tag inline on its vis/symbol entry.

Return the `:observation | :mutation` tag for `op-keyword`. Unknown
ops fail closed; every symbol must declare `:tag` inline on its
`vis/symbol` entry.
sourceraw docstring

open-live-view!clj

source

original-stdoutclj

source

pad-leftclj

(pad-left s w)
source

pad-rightclj

(pad-right s w)
source

paletteclj

Default palette. Kept as a named var for channels that only need colours.

Default palette. Kept as a named var for channels that only need colours.
sourceraw docstring

parse-argsclj

(parse-args arg-specs raw-args)

Parse raw-args against arg-specs. Returns a map of {arg-name value}. Positional specs are matched in order; flag specs by --name; boolean flags need no value. Unknown flags are silently dropped so commands can layer their own loose flags.

Parse `raw-args` against `arg-specs`. Returns a map of
`{arg-name value}`. Positional specs are matched in order; flag
specs by `--name`; boolean flags need no value. Unknown flags
are silently dropped so commands can layer their own loose flags.
sourceraw docstring

parse-block-displayclj

(parse-block-display form-source)

Return the model's authored source as ONE verbatim :code segment.

The engine is full-Python: the source is Python and we keep it VERBATIM here — exactly what the model wrote, no splitting, no classification. This is the canonical segment (tests + the model's own context depend on it being the raw bytes). Channels that want a beautified view call prettify-python at paint time; the IR stays raw.

Pure helper. Never throws. Blank / nil input returns [].

Return the model's authored source as ONE verbatim `:code` segment.

The engine is full-Python: the source is Python and we keep it VERBATIM here —
exactly what the model wrote, no splitting, no classification. This is the
canonical segment (tests + the model's own context depend on it being the raw
bytes). Channels that want a beautified view call `prettify-python` at paint
time; the IR stays raw.

Pure helper. Never throws. Blank / nil input returns `[]`.
sourceraw docstring

patch-live-view!clj

source

pending-human-input-requestclj

source

picker-fleetclj

(picker-fleet)

The provider fleet a model picker should render: the persisted configured-providers first, then authenticated-preset-providers (authenticated-but-unconfigured OAuth providers whose creds live outside config) appended. This is what channel model pickers enumerate so authenticated providers are selectable even before they're saved into the fleet.

Failure-isolated by construction: the base fleet reads through the never-nil configured-providers-cached (no per-open 4-file parse, no render-thread stall), and the authenticated-preset enumeration degrades to empty on any error. A transient hiccup therefore drops the OAuth extras at worst — it NEVER throws and NEVER blanks the picker of already-configured providers.

The provider fleet a model picker should render: the persisted
`configured-providers` first, then `authenticated-preset-providers`
(authenticated-but-unconfigured OAuth providers whose creds live outside
config) appended. This is what channel model pickers enumerate so
authenticated providers are selectable even before they're saved into the
fleet.

Failure-isolated by construction: the base fleet reads through the
never-nil `configured-providers-cached` (no per-open 4-file parse, no
render-thread stall), and the authenticated-preset enumeration degrades to
empty on any error. A transient hiccup therefore drops the OAuth extras at
worst — it NEVER throws and NEVER blanks the picker of already-configured
providers.
sourceraw docstring

prepare-session-jail!clj

(prepare-session-jail! {:keys [session-id jail-policy-fn]})

Bind the language surface's live session env to the managed-process contract. Missing session identity or policy fails closed before a language handler can start a REPL or project test process. Safe and idempotent per dispatch.

Bind the language surface's live session env to the managed-process contract.
Missing session identity or policy fails closed before a language handler can
start a REPL or project test process. Safe and idempotent per dispatch.
sourceraw docstring

providerclj

(provider descriptor)

Build and validate a provider descriptor.

Build and validate a provider descriptor.
sourceraw docstring

provider-auth-kindclj

(provider-auth-kind pid)
(provider-auth-kind pid provider)

How a provider authenticates: :command (an api_key_command mints the credential — never prompt), :oauth (the registered extension declares an interactive :provider/auth-fn), :managed (the extension owns configuration and exposes no interactive flow), :none (local, no credentials), or :api-key.

Ownership never overrides authentication: a managed provider with auth-fn is OAuth-capable while remaining automatically bound and absent from Add Provider. The 1-arity classifies by id alone and therefore can never see a command-minted provider; pass the configured provider map when that answer decides whether to prompt a human.

How a provider authenticates: `:command` (an `api_key_command` mints the
credential — never prompt), `:oauth` (the registered extension declares an
interactive `:provider/auth-fn`), `:managed` (the extension owns configuration
and exposes no interactive flow), `:none` (local, no credentials), or `:api-key`.

Ownership never overrides authentication: a managed provider with `auth-fn` is
OAuth-capable while remaining automatically bound and absent from Add Provider.
The 1-arity classifies by id alone and therefore can never see a command-minted
provider; pass the configured provider map when that answer decides whether to
prompt a human.
sourceraw docstring

provider-base-urlclj

(provider-base-url provider)

Resolve base-url for a provider: explicit field on the provider map first (so user-supplied URLs win), then the merged catalog.

Resolve base-url for a provider: explicit field on the provider
map first (so user-supplied URLs win), then the merged catalog.
sourceraw docstring

provider-by-idclj

(provider-by-id id)

Lookup a provider by :provider/id. Returns nil when absent.

Lookup a provider by `:provider/id`. Returns nil when absent.
sourceraw docstring

provider-command-minted?clj

(provider-command-minted? provider)

True when the credential is minted BY THE MACHINE: config carries an api_key_command, so the helper mints (and rotates) the token on every request and there is nothing for a human to type or paste.

True when the credential is minted BY THE MACHINE: config carries an
`api_key_command`, so the helper mints (and rotates) the token on every
request and there is nothing for a human to type or paste.
sourceraw docstring

provider-config-with-modelsclj

(provider-config-with-models preset models)

Persistable provider config carrying the provider's complete catalog.

Persistable provider config carrying the provider's complete catalog.
sourceraw docstring

provider-configured?clj

(provider-configured?)

True when at least one provider is configured (global or project config). The single predicate entry points use to branch onboarding vs normal start — never trips the resolve-config throw.

True when at least one provider is configured (global or project config).
The single predicate entry points use to branch onboarding vs normal start —
never trips the `resolve-config` throw.
sourceraw docstring

provider-default-model-configsclj

(provider-default-model-configs preset)

Preset :default-models as persisted model maps. A bare-string entry becomes {:name str}; a MAP entry is carried through verbatim (name normalized) so a provider can declare :context / :output-limit / … for a model svar's pinned catalog doesn't know yet — no svar release, no enrich hook. ->svar-model whitelists which of those keys svar honors, so extra keys are harmless.

Preset `:default-models` as persisted model maps. A bare-string entry
becomes `{:name str}`; a MAP entry is carried through verbatim (name
normalized) so a provider can declare `:context` / `:output-limit` / … for
a model svar's pinned catalog doesn't know yet — no svar release, no
enrich hook. `->svar-model` whitelists which of those keys svar honors, so
extra keys are harmless.
sourceraw docstring

provider-default-model-namesclj

(provider-default-model-names provider)

Union of model names already on the provider map plus the preset / provider :default-models, deduped. Config order leads: the models a user wrote in vis.yml come first and model-options keeps them there.

Union of model names already on the provider map plus the preset /
provider `:default-models`, deduped. Config order leads: the models a
user wrote in vis.yml come first and `model-options` keeps them there.
sourceraw docstring

provider-ensure-base-urlclj

(provider-ensure-base-url provider)
source

provider-fetch-modelsclj

(provider-fetch-models provider)

List models for a vis provider via svar/models!.

Returns vec of chat model id strings, or nil on failure. Filters out TTS / embedding / speech / image and provider-excluded models.

Routing through svar means the call automatically picks up provider-specific OAuth headers (anthropic-version, anthropic-beta for the Anthropic Claude subscription; chatgpt-account-id for OpenAI Codex; bare Bearer for everyone else).

provider is a vis-shaped provider map. We coerce to svar shape (resolving OAuth tokens via the provider's :provider/get-token-fn when :api-key is absent) and ask svar.

List models for a vis provider via `svar/models!`.

Returns vec of chat model id strings, or nil on failure. Filters
out TTS / embedding / speech / image and provider-excluded models.

Routing through svar means the call automatically picks up
provider-specific OAuth headers (`anthropic-version`,
`anthropic-beta` for the Anthropic Claude subscription;
`chatgpt-account-id` for OpenAI Codex; bare Bearer for everyone
else).

`provider` is a vis-shaped provider map. We coerce to svar shape
(resolving OAuth tokens via the provider's `:provider/get-token-fn`
when `:api-key` is absent) and ask svar.
sourceraw docstring

provider-idsclj

(provider-ids)

Set of configured provider :id keywords.

Set of configured provider `:id` keywords.
sourceraw docstring

provider-initial-limitsclj

(provider-initial-limits provider)

Placeholder limits report while the real fetch runs.

Placeholder limits report while the real fetch runs.
sourceraw docstring

provider-initial-statusclj

(provider-initial-status provider)

Placeholder status while a real probe runs in the background. A credential gap is decided synchronously — it is a pure read of the config already in hand, plus at most one cached credential-command probe — so the card never flashes an authenticated verdict it is about to retract.

Placeholder status while a real probe runs in the background. A credential gap
is decided synchronously — it is a pure read of the config already in hand,
plus at most one cached credential-command probe — so the card never flashes
an authenticated verdict it is about to retract.
sourceraw docstring

provider-key-detectclj

(provider-key-detect book plan-tag)

Lookup priority for one plan:

  1. TUI/config provider :api-key for this plan.
  2. The plan's env-var chain.
  3. The book's file slice for this plan. Returns {:api-key str :source kw} or nil. Never throws.

:source is :config, :env-var or :auth-file, so a status report can tell the user WHERE the key came from.

Lookup priority for one plan:
  1. TUI/config provider `:api-key` for this plan.
  2. The plan's env-var chain.
  3. The book's file slice for this plan.
Returns `{:api-key str :source kw}` or nil. Never throws.

`:source` is `:config`, `:env-var` or `:auth-file`, so a status report can
tell the user WHERE the key came from.
sourceraw docstring

provider-key-entriesclj

(provider-key-entries book limits-fn)

One :ext/providers entry per plan in the book, in plan order. limits-fn is (fn [plan-tag] (fn [] report)) because a quota endpoint - or the absence of one - is the vendor's own business.

One `:ext/providers` entry per plan in the book, in plan order.
`limits-fn` is `(fn [plan-tag] (fn [] report))` because a quota endpoint -
or the absence of one - is the vendor's own business.
sourceraw docstring

provider-limitsclj

(provider-limits provider-id)

Return a normalized, contract-validated limits report for one provider id.

The provider's optional :provider/limits-fn supplies the dynamic portion. This host wrapper backfills static svar metadata and always returns a valid contract-provider/report envelope, even when the provider-specific implementation is absent, missing, throws, or returns malformed data.

Providers that only have static svar catalog metadata still return a usable :ok report so callers can surface RPM / TPM without needing a registered runtime extension.

Return a normalized, contract-validated limits report for one provider id.

The provider's optional `:provider/limits-fn` supplies the dynamic
portion. This host wrapper backfills static svar metadata and always
returns a valid `contract-provider/report` envelope, even when the
provider-specific implementation is absent, missing, throws, or returns
malformed data.

Providers that only have static svar catalog metadata still return a
usable `:ok` report so callers can surface RPM / TPM without needing a
registered runtime extension.
sourceraw docstring

provider-limits-safeclj

(provider-limits-safe provider)

Normalized limits report for a provider id; an error report instead of a throw, and never slower than limits-probe-timeout-ms.

A late probe is deliberately NOT cancelled: provider-limits memoizes the report it is still computing, so abandoning this read leaves the next one warm.

Normalized limits report for a provider id; an error report instead
of a throw, and never slower than `limits-probe-timeout-ms`.

A late probe is deliberately NOT cancelled: `provider-limits` memoizes the
report it is still computing, so abandoning this read leaves the next one warm.
sourceraw docstring

provider-local-no-auth-idsclj

Local OpenAI-compatible providers that need no credentials.

Local OpenAI-compatible providers that need no credentials.
sourceraw docstring

provider-managed?clj

(provider-managed? provider-id)

True when the extension that registered provider-id owns its binding and configuration. Managed providers bind as soon as their extension loads and stay out of Add Provider. Authentication is independent: :provider/auth-fn may still obtain a provider-owned credential on first use.

True when the extension that registered `provider-id` owns its binding and
configuration. Managed providers bind as soon as their extension loads and stay
out of Add Provider. Authentication is independent: `:provider/auth-fn` may still
obtain a provider-owned credential on first use.
sourceraw docstring

provider-model-optionsclj

(provider-model-options provider)
(provider-model-options provider default-models show-all?)

Selectable model ids for a provider: configured models first IN vis.yml ORDER, then live-fetched + preset defaults deduped and sorted, env default pinned first. When show-all? is false, dated snapshot variants (gpt-4o-2024-08-06) are hidden.

Returns {:models [id ...] :hidden-count n} - channels render their own 'show all' affordance from :hidden-count.

Selectable model ids for a provider: configured models first IN vis.yml
ORDER, then live-fetched + preset defaults deduped and sorted, env
default pinned first. When `show-all?` is false, dated snapshot
variants (gpt-4o-2024-08-06) are hidden.

Returns `{:models [id ...] :hidden-count n}` - channels render
their own 'show all' affordance from `:hidden-count`.
sourceraw docstring

provider-model-visible?clj

(provider-model-visible? provider-id model-id)

True when svar's provider-scoped model filters allow this model id.

True when svar's provider-scoped model filters allow this model id.
sourceraw docstring

provider-oauth-idsclj

Providers whose credentials come from an interactive OAuth flow and live OUTSIDE config.edn (keychain / token files owned by the provider extension).

Providers whose credentials come from an interactive OAuth flow and
live OUTSIDE config.edn (keychain / token files owned by the
provider extension).
sourceraw docstring

provider-persisted-configclj

(provider-persisted-config provider)

Convert an in-memory provider entry to the durable on-disk shape.

Convert an in-memory provider entry to the durable on-disk shape.
sourceraw docstring

provider-presetsclj

(provider-presets)

All known provider presets, sorted for the 'Add Provider' picker.

All known provider presets, sorted for the 'Add Provider' picker.
sourceraw docstring

provider-presets-availableclj

(provider-presets-available)

Provider presets not yet in the configured fleet — the 'Add Provider' picker contents.

A MANAGED provider is never offered here: it carries no credential a human supplies and it binds itself, so an Add provider row for it could only ask for a key that every seam below must refuse.

Provider presets not yet in the configured fleet — the 'Add
Provider' picker contents.

A MANAGED provider is never offered here: it carries no credential a human
supplies and it binds itself, so an `Add provider` row for it could only ask
for a key that every seam below must refuse.
sourceraw docstring

provider-statusclj

(provider-status provider)

Auth/liveness status for a CONFIGURED provider map, with one explicit :auth-state every channel paints:

  • :verified — a live provider check accepted the credential,
  • :rejected — the credential/config was explicitly refused,
  • :degraded — the credential remains usable but its live check failed,
  • :unverified — a credential exists but no live check can prove it (or no credential exists yet).

:is-authenticated remains the independent usability bit: a degraded or unverified entry can still route only when it is true; rejection forces it false. Never throws.

Auth/liveness status for a CONFIGURED provider map, with one explicit
`:auth-state` every channel paints:

- `:verified` — a live provider check accepted the credential,
- `:rejected` — the credential/config was explicitly refused,
- `:degraded` — the credential remains usable but its live check failed,
- `:unverified` — a credential exists but no live check can prove it (or
  no credential exists yet).

`:is-authenticated` remains the independent usability bit: a degraded or
unverified entry can still route only when it is true; rejection forces it false.
Never throws.
sourceraw docstring

provider-status-mdclj

(provider-status-md provider)
(provider-status-md provider status limits)

The provider status + limits report as MARKDOWN — one rich canonical form every channel renders natively: the web through its markdown pipeline and the TUI through its transient Markdown layout walker. The same facts as [[status-text]], structured instead of flat.

The provider status + limits report as MARKDOWN — one rich canonical
form every channel renders natively: the web through its markdown
pipeline and the TUI through its transient Markdown layout walker. The same
facts as [[status-text]], structured instead of flat.
sourceraw docstring

provider-status-of-registeredclj

(provider-status-of-registered provider)

Status of a REGISTERED provider descriptor via its :provider/status-fn (falling back to :provider/detect-fn). Never throws, and never runs longer than probe-timeout-ms: a callback that is still going by then answers {:is-authenticated false :error "…timed out…"} — an honest verdict the surface can paint — instead of parking the thread that asked.

Status of a REGISTERED provider descriptor via its `:provider/status-fn`
(falling back to `:provider/detect-fn`). Never throws, and never runs longer
than `probe-timeout-ms`: a callback that is still going by then answers
`{:is-authenticated false :error "…timed out…"}` — an honest verdict the
surface can paint — instead of parking the thread that asked.
sourceraw docstring

provider-status-textclj

(provider-status-text provider)
(provider-status-text provider status limits)

Multi-line human status + limits report for a configured provider. The single source for the TUI 'Show Status + Limits' dialog and the web status view.

Multi-line human status + limits report for a configured provider.
The single source for the TUI 'Show Status + Limits' dialog and the
web status view.
sourceraw docstring

provider-templateclj

(provider-template pid)

Preset descriptor for a provider id, merged from a provider extension's metadata and svar's catalog. Returns nil for unknown or intentionally removed ids.

Preset descriptor for a provider id, merged from a provider
extension's metadata and svar's catalog. Returns nil for unknown or
intentionally removed ids.
sourceraw docstring

provider-url-hostclj

(provider-url-host url)

Extract host from URL for display. 'https://llm.blockether.com/v1' -> 'llm.blockether.com'.

Extract host from URL for display. 'https://llm.blockether.com/v1' ->
'llm.blockether.com'.
sourceraw docstring

publish-channel-event!clj

source

python-extension-load-failuresclj

(python-extension-load-failures)

Load failures from the latest scan. Each row names the file, error, retained extension, stale? status, loaded/requested source fingerprints and readiness changes.

Load failures from the latest scan. Each row names the file, error, retained
extension, stale? status, loaded/requested source fingerprints and readiness changes.
sourceraw docstring

reasoning->astclj

(reasoning->ast text)

Reasoning / thinking text -> canonical transient Markdown tree. The SINGLE shared entry point for rendering a model's thinking trace (TUI thinking bubble AND the web thinking card), so both channels paint the SAME structure. Reasoning is line-oriented (a trace, not flowing prose): normalize via normalize-reasoning then lift every bare newline to a HARD break ([:br]) via {:soft-break :hard}. Without the hard break a bold heading collapses onto its body line (the TUI **heading** body bug); with it the heading keeps its own line, matching the web ticker's marked({:breaks true}).

Reasoning / thinking text -> canonical transient Markdown tree. The SINGLE shared entry
point for rendering a model's thinking trace (TUI thinking bubble AND the web
thinking card), so both channels paint the SAME structure. Reasoning is
line-oriented (a trace, not flowing prose): normalize via `normalize-reasoning`
then lift every bare newline to a HARD break (`[:br]`) via `{:soft-break
:hard}`. Without the hard break a bold heading collapses onto its body line
(the TUI `**heading** body` bug); with it the heading keeps its own line,
matching the web ticker's `marked({:breaks true})`.
sourceraw docstring

reasoning-collapse-min-hiddenclj

Minimum HIDDEN reasoning rows required before a thinking trace collapses. One or two surplus rows stay inline because a disclosure would add more friction than space savings.

Minimum HIDDEN reasoning rows required before a thinking trace collapses.
One or two surplus rows stay inline because a disclosure would add more
friction than space savings.
sourceraw docstring

reasoning-effort-configurable?clj

(reasoning-effort-configurable? resolved-model)

True when a model accepts a CALLER-selected reasoning effort.

svar decides this, not Vis: :reasoning-effort? is stamped on every model the router normalizes, from the WIRE that model rides. :reasoning? only says the model thinks — GitHub Copilot's Gemini/Grok tiers think but are :server-managed on the OpenAI-compatible wire, and Z.ai GLM thinking is binary, so neither accepts a depth and neither may show a depth control. Copilot's Claude tier rides the native Anthropic wire and DOES take one.

True when a model accepts a CALLER-selected reasoning effort.

svar decides this, not Vis: `:reasoning-effort?` is stamped on every model
the router normalizes, from the WIRE that model rides. `:reasoning?` only
says the model thinks — GitHub Copilot's Gemini/Grok tiers think but are
`:server-managed` on the OpenAI-compatible wire, and Z.ai GLM thinking is
binary, so neither accepts a depth and neither may show a depth control.
Copilot's Claude tier rides the native Anthropic wire and DOES take one.
sourceraw docstring

reasoning-preview-line-limitclj

Canonical reasoning PREVIEW height shared by every channel. Up to this many rows/lines of a thinking trace stay visible; the remainder folds behind a +N more disclosure (web) / ▸ THINKING +N more toggle (TUI). One source of truth so the TUI bubble and the web card clamp reasoning to the SAME height.

Canonical reasoning PREVIEW height shared by every channel. Up to this many
rows/lines of a thinking trace stay visible; the remainder folds behind a
`+N more` disclosure (web) / `▸ THINKING +N more` toggle (TUI). One
source of truth so the TUI bubble and the web card clamp reasoning to the
SAME height.
sourceraw docstring

rebuild-router!clj

(rebuild-router! config)

Rebuild the router from the given config. Used when provider settings change.

Forwards :router opts so live config edits (e.g. tuning :same-provider-delays-ms) take effect on the next set-provider! without restarting the JVM.

Rebuild the router from the given config. Used when provider settings change.

Forwards `:router` opts so live config edits (e.g. tuning
`:same-provider-delays-ms`) take effect on the next `set-provider!`
without restarting the JVM.
sourceraw docstring

refresh-cached-routers!clj

(refresh-cached-routers! router)

Reseat :router on every cached env's environment map.

create-environment snapshots the router into (:router env) at construction time, and the iteration loop calls (svar/ask-code! (:router environment) ...) - not the global router-atom. So when a frontend changes provider config and rebuilds the global router, every long-lived env in the cache (TUI keeps one for the whole session) keeps talking to the previous model until disposed.

Provider kickoff hooks run against each session before its new snapshot is seated, covering providers added or reconfigured while that session is live. A failed kickoff aborts the reseat instead of installing incomplete metadata. Call this immediately after rebuild-router! so the next send! on any cached session picks up the new router.

Reseat `:router` on every cached env's environment map.

`create-environment` snapshots the router into
`(:router env)` at construction time, and the iteration loop calls
`(svar/ask-code! (:router environment) ...)` - not the global
`router-atom`. So when a frontend changes provider
config and rebuilds the global router, every long-lived env in the
cache (TUI keeps one for the whole session) keeps talking to the
*previous* model until disposed.

Provider kickoff hooks run against each session before its new snapshot is
seated, covering providers added or reconfigured while that session is live.
A failed kickoff aborts the reseat instead of installing incomplete metadata.
Call this immediately after `rebuild-router!` so the next `send!` on any cached
session picks up the new router.
sourceraw docstring

register-channel!clj

(register-channel! spec)

Register a channel in the global registry. Idempotent on :channel/id - re-registering replaces the prior spec. Returns the validated channel.

Register a channel in the global registry.
Idempotent on :channel/id - re-registering replaces the prior spec.
Returns the validated channel.
sourceraw docstring

register-cmd!clj

(register-cmd! spec)

Register a command in the global registry. Idempotent on [:cmd/parent :cmd/name] - re-registering replaces the prior entry, useful for REPL-driven development. Returns the validated command map.

Register a command in the global registry. Idempotent on
`[:cmd/parent :cmd/name]` - re-registering replaces the prior
entry, useful for REPL-driven development. Returns the validated
command map.
sourceraw docstring

register-extension!clj

(register-extension! ext)

Register an extension in the global process-level registry.

This is THE single entry point for everything an extension contributes to vis. Whatever the extension declares -- Python sandbox symbols (:ext.engine/symbols), CLI commands (:ext/cli), channels (:ext/channels), LLM providers (:ext/providers) -- gets routed here and dispatched into the matching sub-registry as a side effect.

Also computes source-file markers (paths, max-mtime, sha256) and stores them in a sidecar atom read by the tool-envelope emitter (UI extension provenance label).

Idempotent on :ext/name. Returns the validated extension.

Register an extension in the global process-level registry.

This is THE single entry point for everything an extension
contributes to vis. Whatever the extension declares -- Python sandbox
symbols (`:ext.engine/symbols`), CLI commands (`:ext/cli`), channels
(`:ext/channels`), LLM providers (`:ext/providers`) -- gets routed here and dispatched into
the matching sub-registry as a side effect.

Also computes source-file markers (paths, max-mtime, sha256) and
stores them in a sidecar atom read by the tool-envelope emitter
(UI extension provenance label).

Idempotent on `:ext/name`. Returns the validated extension.
sourceraw docstring

register-op-hook!clj

(register-op-hook! {:keys [op phase owner] hook-fn :fn :or {phase :after}})

Register a cross-cutting hook on operation :op (its op-keyword, e.g. :patch). :phase is :after (default — sees & may rewrite the result envelope), :before (sees & may rewrite the args vector), :around (MIDDLEWARE — wraps the call), or :gate (the op is ASKED, never wrapped — see gate-ops; a gate op forces this phase whatever the caller declared, because the op decides the shape). :fn is, for :after, (fn [env op-kw args result] -> result-envelope); for :before, (fn [env op-kw args] -> args-vector); for :around, (fn [env op-kw args next] -> result) where next runs the inner call and may be invoked zero+ times (skip / retry) or wrapped in try/catch (recover — this is how an op is made NOT to fail); for :gate, (fn [env op-kw ctx] -> nil | reason). :owner (an ext keyword) makes the registration idempotent across :reloads — re-registering the same owner+phase for an op REPLACES the prior one. Returns the op-keyword.

Register a cross-cutting hook on operation `:op` (its op-keyword, e.g.
:patch). `:phase` is :after (default — sees & may rewrite the result
envelope), :before (sees & may rewrite the args vector), :around (MIDDLEWARE
— wraps the call), or :gate (the op is ASKED, never wrapped — see `gate-ops`;
a gate op forces this phase whatever the caller declared, because the op
decides the shape). `:fn` is, for :after, (fn [env op-kw args result] ->
result-envelope); for :before, (fn [env op-kw args] -> args-vector); for
:around, (fn [env op-kw args next] -> result) where `next` runs the inner call
and may be invoked zero+ times (skip / retry) or wrapped in try/catch (recover
— this is how an op is made NOT to fail); for :gate, (fn [env op-kw ctx] ->
nil | reason). `:owner` (an ext keyword) makes the registration idempotent
across `:reload`s — re-registering the same owner+phase for an op REPLACES the
prior one. Returns the op-keyword.
sourceraw docstring

register-provider!clj

(register-provider! spec)

Register a provider in the global registry. Idempotent on :provider/id - re-registering replaces the previous descriptor. Returns the validated provider.

Register a provider in the global registry. Idempotent on
`:provider/id` - re-registering replaces the previous descriptor.
Returns the validated provider.
sourceraw docstring

register-resource!clj

(register-resource! session resource)
(register-resource! session
                    resource
                    {:keys [stop-fn alive-fn logs-fn health-fn] :as fns})

Register (or replace) a resource UNDER session. resource is the DATA map (needs at least :id, unique within the session; :kind defaults to :resource). fns carries the live lifecycle thunks {:stop-fn :alive-fn :logs-fn :health-fn} (all optional — a resource with no :stop-fn reports can_stop false). Returns the stored DATA map.

Register (or replace) a resource UNDER `session`. `resource` is the DATA map
(needs at least `:id`, unique within the session; `:kind` defaults to
`:resource`). `fns` carries the live lifecycle thunks `{:stop-fn
:alive-fn :logs-fn :health-fn}` (all optional — a resource with no `:stop-fn`
reports `can_stop false`). Returns the stored DATA map.
sourceraw docstring

register-theme!clj

(register-theme! theme-map)
(register-theme! id theme-map)

Add or replace one theme in the process registry.

Arity 1 expects a full theme map with :name. Arity 2 accepts either a full theme map or a compact settings map such as {"PADDING" "0px"}.

Add or replace one theme in the process registry.

Arity 1 expects a full theme map with `:name`. Arity 2 accepts either a
full theme map or a compact settings map such as `{"PADDING" "0px"}`.
sourceraw docstring

register-themes!clj

(register-themes! theme-map)

Add every entry from an extension-style theme map.

{"THEME_NAME" {"PADDING" "0px"}}

Values may be compact settings maps or full theme maps.

Add every entry from an extension-style theme map.

  {"THEME_NAME" {"PADDING" "0px"}}

Values may be compact settings maps or full theme maps.
sourceraw docstring

register-toggle!clj

(register-toggle! contribution)

Register one toggle that satisfies the contract-owned contribution shape.

Re-registering the same :id is idempotent: metadata MERGES, the live VALUE in state is preserved (user overrides survive reload). Returns the normalized contribution.

Register one toggle that satisfies the contract-owned contribution shape.

Re-registering the same `:id` is idempotent: metadata MERGES, the
live VALUE in `state` is preserved (user overrides survive reload).
Returns the normalized contribution.
sourceraw docstring

register-toggles!clj

(register-toggles! specs)

Convenience: register a sequence of specs in order, returns the vec of canonical specs.

Convenience: register a sequence of specs in order, returns the
vec of canonical specs.
sourceraw docstring

registered-channelsclj

(registered-channels)

All globally registered channels as a vector.

All globally registered channels as a vector.
sourceraw docstring

registered-commandsclj

(registered-commands)

Return all registered commands as a vector, in registration order.

Return all registered commands as a vector, in registration order.
sourceraw docstring

registered-extensionsclj

(registered-extensions)
source

registered-providersclj

(registered-providers)
source

registered-slashesclj

(registered-slashes)

Walk every globally registered extension and return the union of their :ext/slash-commands specs. Activation-fn filtering is NOT applied here — channels that surface slash UX before a session is running (TUI palette overlay) use this env-less view. The engine dispatch path itself goes through active-slashes env so per-session activation-fn rules still hold.

Walk every globally registered extension and return the union of
their `:ext/slash-commands` specs. Activation-fn filtering is NOT
applied here — channels that surface slash UX before a session is
running (TUI palette overlay) use this
env-less view. The engine dispatch path itself goes through
`active-slashes env` so per-session activation-fn rules still hold.
sourceraw docstring

registered-togglesclj

(registered-toggles)

Vec of every registered toggle's normalized spec, in registration insertion order. Stable for the TUI settings dialog.

Vec of every registered toggle's normalized spec, in registration
insertion order. Stable for the TUI settings dialog.
sourceraw docstring

registered-underclj

(registered-under parent-path)

Return the vector of registered commands whose :cmd/parent equals parent-path (a vector of names). Use this from a parent command's :cmd/subcommands slot - typically as a 0-arg fn so newly registered children appear immediately:

{:cmd/name "extension"
 :cmd/doc  "Run an extension command."
 :cmd/subcommands #(registered-under ["extension"])}
Return the vector of registered commands whose `:cmd/parent` equals
`parent-path` (a vector of names). Use this from a parent command's
`:cmd/subcommands` slot - typically as a 0-arg fn so newly
registered children appear immediately:

    {:cmd/name "extension"
     :cmd/doc  "Run an extension command."
     :cmd/subcommands #(registered-under ["extension"])}
sourceraw docstring

reload-config!clj

(reload-config!)
source

reload-python-extensions!clj

(reload-python-extensions!)
(reload-python-extensions! opts)

Force a full reload of every Python extension (even when no file changed). Same return shape as load-python-extensions!. Live sessions pick the new tool bindings up at the next turn boundary.

Force a full reload of every Python extension (even when no file
changed). Same return shape as `load-python-extensions!`. Live
sessions pick the new tool bindings up at the next turn boundary.
sourceraw docstring

remove-channel-event-listener!clj

source

remove-config-provider!clj

(remove-config-provider! provider-id)
(remove-config-provider! provider-id source)

Remove every persisted provider entry for provider-id from the string-keyed machine config, preserving unrelated keys.

A FALLBACK tag naming that provider goes with it. Unlike default_provider, which degrades to the fleet's first provider, the fallback root is never implicit: a tag left behind names nobody, is invisible to every UI, and silently resurrects the moment that provider is authenticated again.

Remove every persisted provider entry for `provider-id` from the string-keyed
machine config, preserving unrelated keys.

A FALLBACK tag naming that provider goes with it. Unlike `default_provider`,
which degrades to the fleet's first provider, the fallback root is never
implicit: a tag left behind names nobody, is invisible to every UI, and
silently resurrects the moment that provider is authenticated again.
sourceraw docstring

remove-provider!clj

(remove-provider! provider-id)
(remove-provider! provider-id source)

Remove a provider from the persisted fleet AND run the registered extension's logout when present. Invalidates the fleet snapshot. Returns true when config changed. Extension-managed providers are rejected before logout or any config mutation with :type :provider/managed.

Remove a provider from the persisted fleet AND run the registered
extension's logout when present. Invalidates the fleet snapshot.
Returns true when config changed. Extension-managed providers are rejected
before logout or any config mutation with `:type :provider/managed`.
sourceraw docstring

remove-python-extension-change-listener!clj

(remove-python-extension-change-listener! listener-id)

Remove a listener registered with [[add-change-listener!]]. Returns nil.

Remove a listener registered with [[add-change-listener!]]. Returns nil.
sourceraw docstring

remove-title-listener!clj

(remove-title-listener! session-id listener-fn)

Deregister a previously added listener. Idempotent.

Deregister a previously added listener. Idempotent.
sourceraw docstring

remove-title-pending-listener!clj

(remove-title-pending-listener! session-id listener-fn)

Deregister a previously added pending listener. Idempotent.

Deregister a previously added pending listener. Idempotent.
sourceraw docstring

renderclj

(render input flavor)
(render input flavor opts)

Render any answer input into a flavor.

Input: string | Hiccup vector | [:ast ...] AST | sequential of mixed Flavor: :html | :markdown | :plain Opts: {:context #{:answer :thinking :status :error} :max-length int - hard cap; truncate at paragraph boundary}

Render any answer input into a flavor.

Input:  string | Hiccup vector | [:ast ...] AST | sequential of mixed
Flavor: :html | :markdown | :plain
Opts:   {:context    #{:answer :thinking :status :error}
         :max-length int  - hard cap; truncate at paragraph boundary}
sourceraw docstring

render-commandclj

(render-command cmd path)

Render multi-section help for a single command: USAGE / DESCRIPTION / SUBCOMMANDS / ARGUMENTS / FLAGS / EXAMPLES.

Empty sections are omitted. path is the command-name chain leading up to and including this command - used for the USAGE line when :cmd/usage isn't set.

Render multi-section help for a single command:
  USAGE / DESCRIPTION / SUBCOMMANDS / ARGUMENTS / FLAGS / EXAMPLES.

Empty sections are omitted. `path` is the command-name chain
leading up to and including this command - used for the USAGE line
when `:cmd/usage` isn't set.
sourceraw docstring

render-form-valueclj

(render-form-value _src v)

THE model-facing string for one tool/form VALUE: the canonical STRUCTURED serialization of the result, and nothing else. Tools return maps or vectors and the model reads them as DATA — there is NO per-tool rendering, no hash-gutter file views, no rg grouping.

:op (the call head) is stripped from maps since the call is already visible in the assistant replay; src is accepted for call-site compatibility but no longer affects the output. Structural results carry plain 1-based line/end_line numbers, so editing resolves straight off this structured data.

THE model-facing string for one tool/form VALUE: the canonical
STRUCTURED serialization of the result, and nothing else. Tools return
maps or vectors and the model reads them as DATA — there is NO per-tool
rendering, no hash-gutter file views, no rg grouping.

`:op` (the call head) is stripped from maps since the call is already
visible in the assistant replay; `src` is accepted for call-site
compatibility but no longer affects the output. Structural results carry
plain 1-based `line`/`end_line` numbers, so editing resolves straight off
this structured data.
sourceraw docstring

render-promptclj

(render-prompt {:keys [heading usage-note notes] :as opts})

Render canonical :ext/prompt-fn text for an extension's symbols.

A prompt fragment states ROUTING and POLICY only: when this extension is the right approach, and what it refuses. It NEVER restates a signature, an argument name, a return shape or an example call — that text is the symbol's own :ext.symbol/description, reached on demand with doc(name). A fragment is pushed into EVERY request; a docstring is pulled once, so a signature copied up here is paid for on every turn and drifts from the one that runs.

Accepts an extension map or any map with:

  • :ext/description or :heading
  • :ext.engine/alias optional {:alias 'v}
  • :ext.engine/symbols vector of symbol + value entries
  • :usage-note optional extra note added to the heading
  • :notes optional string or seq of extra lines appended verbatim

Returns a prompt string suitable for :ext/prompt-fn.

Render canonical `:ext/prompt-fn` text for an extension's symbols.

A prompt fragment states ROUTING and POLICY only: when this extension is the
right approach, and what it refuses. It NEVER restates a signature, an
argument name, a return shape or an example call — that text is the symbol's
own `:ext.symbol/description`, reached on demand with `doc(name)`. A fragment
is pushed into EVERY request; a docstring is pulled once, so a signature
copied up here is paid for on every turn and drifts from the one that runs.

Accepts an extension map or any map with:
- :ext/description      or :heading
- :ext.engine/alias optional {:alias 'v}
- :ext.engine/symbols  vector of symbol + value entries
- :usage-note   optional extra note added to the heading
- :notes        optional string or seq of extra lines appended verbatim

Returns a prompt string suitable for :ext/prompt-fn.
sourceraw docstring

render-treeclj

(render-tree root)

Top-level overview rendered when the binary is invoked with no arguments (or via vis-agent help). Shows the root doc, then a single COMMANDS block listing every immediate subcommand.

Top-level overview rendered when the binary is invoked with no
arguments (or via `vis-agent help`). Shows the root doc, then a single
COMMANDS block listing every immediate subcommand.
sourceraw docstring

repository-inventoryclj

(repository-inventory root)
(repository-inventory root opts)

Return a lightweight, cached inventory of Git roots below root.

Unlike snapshot, this performs no per-repository Git status work and is suitable for extension discovery. Known VCS metadata, cache, vendor, and build directories are skipped. The default scan is bounded at 64 repositories.

Shape: {:root <abs-root> :count 2 :repositories [{:path <relative-path> :root <abs-root>} ...] :truncated? false}

Return a lightweight, cached inventory of Git roots below `root`.

Unlike `snapshot`, this performs no per-repository Git status work and is
suitable for extension discovery. Known VCS metadata, cache, vendor, and
build directories are skipped. The default scan is bounded at 64
repositories.

Shape:
  {:root <abs-root>
   :count 2
   :repositories [{:path <relative-path> :root <abs-root>} ...]
   :truncated? false}
sourceraw docstring

request-human-input!clj

source

reset-themes!clj

(reset-themes!)

Reset process registry to built-in themes. Test/dev helper.

Reset process registry to built-in themes. Test/dev helper.
sourceraw docstring

resolve-configclj

(resolve-config)
(resolve-config explicit-config)

Resolve provider config: explicit -> merged YAML config. Throws when nothing is available.

Resolve provider config: explicit -> merged YAML config.
Throws when nothing is available.
sourceraw docstring

resolve-db-specclj

(resolve-db-spec)
(resolve-db-spec explicit-db-spec)

Resolve DB spec: explicit -> JVM property -> environment -> validated YAML -> default.

Resolve DB spec: explicit -> JVM property -> environment -> validated YAML -> default.
sourceraw docstring

resolve-default-selectionclj

(resolve-default-selection cfg fleet)

PURE: the valid PRIMARY provider/model pair cfg's tags name within fleet. Explicit config wins; an untagged config falls back to the first provider and its first model, so a fleet always HAS a primary root while it has a provider.

Pure because every surface must resolve the tag the way the router does — channels hold the config they just read, and a channel that re-read global state here would answer for a different machine's config in a test and for a stale one in a race.

PURE: the valid PRIMARY provider/model pair `cfg`'s tags name within `fleet`.
Explicit config wins; an untagged config falls back to the first provider and
its first model, so a fleet always HAS a primary root while it has a provider.

Pure because every surface must resolve the tag the way the router does —
channels hold the config they just read, and a channel that re-read global
state here would answer for a different machine's config in a test and for a
stale one in a race.
sourceraw docstring

resolve-effective-modelclj

(resolve-effective-model router)
(resolve-effective-model router _routing-overrides)

Best-effort root model descriptor from router config.

The returned map carries :name (model id, e.g. "gpt-4o") AND :provider (provider id keyword, e.g. :openai) so every caller can persist BOTH alongside the model. Earlier versions returned just the model map and the provider id was silently dropped on the way to the DB - leaving the meta layer with no way to render provider/model.

Best-effort root model descriptor from router config.

The returned map carries `:name` (model id, e.g. "gpt-4o") AND
`:provider` (provider id keyword, e.g. `:openai`) so every caller
can persist BOTH alongside the model. Earlier versions returned
just the model map and the provider id was silently dropped on
the way to the DB - leaving the meta layer with no way to render
`provider/model`.
sourceraw docstring

resolve-model-infoclj

(resolve-model-info router provider-id model-name)

Resolved model map for the model a SESSION actually routes to.

resolve-effective-model answers a different question — the router's GLOBAL root — and a channel that asks it about a session's capabilities describes the wrong model whenever the session picked something else (which is the normal case: Ctrl+T and the web picker both write a per-session preference). provider-id/model-name come from that preference; either may be nil, and the first provider/model that matches what IS given wins. Falls back to the root model so a session with no preference still gets an answer.

Resolved model map for the model a SESSION actually routes to.

`resolve-effective-model` answers a different question — the router's GLOBAL
root — and a channel that asks it about a session's capabilities describes
the wrong model whenever the session picked something else (which is the
normal case: Ctrl+T and the web picker both write a per-session preference).
`provider-id`/`model-name` come from that preference; either may be nil, and
the first provider/model that matches what IS given wins. Falls back to the
root model so a session with no preference still gets an answer.
sourceraw docstring

resolve-subcommandsclj

(resolve-subcommands cmd)

Return the static vector of subcommands, calling the dynamic fn when needed. Returns [] when the command has no children.

Return the static vector of subcommands, calling the dynamic fn
when needed. Returns `[]` when the command has no children.
sourceraw docstring

resource-logsclj

(resource-logs session id)

Captured output lines for session+id, via the resource's :logs-fn thunk. Returns a vector of line strings (newest last), or nil when the resource has no logs-fn (can_logs false) or is unknown. Shell backgrounds expose their ring buffer; managed language REPLs can expose launcher logs.

Captured output lines for `session`+`id`, via the resource's `:logs-fn` thunk.
Returns a vector of line strings (newest last), or nil when the resource has
no logs-fn (`can_logs false`) or is unknown. Shell backgrounds expose their
ring buffer; managed language REPLs can expose launcher logs.
sourceraw docstring

result-cardclj

(result-card {:keys [op] :as form})

Canonical result CARD descriptor derived only from the form's :stdout:

{:op grep — optional form metadata :body …markdown… — local projection of printed output :collapsible? true}

nil means the form printed nothing. A label or operation can never manufacture successful output.

Canonical result CARD descriptor derived only from the form's `:stdout`:

  {:op           `grep`       — optional form metadata
   :body         …markdown…    — local projection of printed output
   :collapsible? true}

nil means the form printed nothing. A label or operation can never manufacture
successful output.
sourceraw docstring

reveal-human-input-secretclj

source

router-initialized?clj

(router-initialized?)

True once the shared router has been built (via get-router/rebuild-router!). Lets a frontend defer the FIRST build to lazy first-use instead of forcing it at startup — so OAuth token fetches (Copilot/Codex) never run at TUI boot.

True once the shared router has been built (via `get-router`/`rebuild-router!`).
Lets a frontend defer the FIRST build to lazy first-use instead of forcing it
at startup — so OAuth token fetches (Copilot/Codex) never run at TUI boot.
sourceraw docstring

router-optsclj

(router-opts config)

Extracts svar/make-router opts from a Vis config map.

Reads the :router block from the merged YAML config:

{:router
 {:rate-limit {:same-provider-delays-ms [2000 3000 6000]
               :fallback-after-ms 30000
               :respect-retry-after? true
               :fallback-provider? true}
  :network    {:timeout-ms 300000 :idle-timeout-ms 45000}
  :budget     {:max-tokens 1000000 :max-cost 5.0}}}

Returns {} when no :router block is present so svar's built-in defaults win. Unknown keys are dropped — only the keys svar's make-router knows about flow through.

See com.blockether.svar.internal.router/make-router for the authoritative key reference.

Extracts `svar/make-router` opts from a Vis config map.

Reads the `:router` block from the merged YAML config:

```clojure
{:router
 {:rate-limit {:same-provider-delays-ms [2000 3000 6000]
               :fallback-after-ms 30000
               :respect-retry-after? true
               :fallback-provider? true}
  :network    {:timeout-ms 300000 :idle-timeout-ms 45000}
  :budget     {:max-tokens 1000000 :max-cost 5.0}}}
```

Returns `{}` when no `:router` block is present so svar's built-in
defaults win. Unknown keys are dropped — only the keys svar's
`make-router` knows about flow through.

See `com.blockether.svar.internal.router/make-router` for the
authoritative key reference.
sourceraw docstring

run-doctor-checksclj

(run-doctor-checks environment)

Run host-owned diagnostics, including speech, then every registered extension's checks.

Run host-owned diagnostics, including speech, then every registered extension's checks.
sourceraw docstring

runtime-configclj

(runtime-config v)

Adapt an already-validated string-keyed YAML map to Vis' internal domain maps. Only the finite keys in runtime-keywords become keywords. User-defined map keys remain strings, and parsing/validation never uses this adapter.

Adapt an already-validated string-keyed YAML map to Vis' internal domain maps.
Only the finite keys in `runtime-keywords` become keywords. User-defined map keys
remain strings, and parsing/validation never uses this adapter.
sourceraw docstring

save-config!clj

(save-config! config)
(save-config! config source)

Persist configuration to ~/.vis/state.yml using the string-keyed YAML contract. Callers may supply internal keyword-keyed domain maps; validation always runs on the exact string-keyed map that is written.

This REPLACES the whole store. Anything that reads the store in order to change PART of it goes through update-machine-config! instead — a bare read-modify-write here silently drops whatever another writer stored in between.

Persist configuration to `~/.vis/state.yml` using the string-keyed YAML contract.
Callers may supply internal keyword-keyed domain maps; validation always runs on
the exact string-keyed map that is written.

This REPLACES the whole store. Anything that reads the store in order to change
PART of it goes through `update-machine-config!` instead — a bare
read-modify-write here silently drops whatever another writer stored in between.
sourceraw docstring

save-config-providers!clj

(save-config-providers! providers)
(save-config-providers! providers source)

Replace the provider vector in the global string-keyed config while preserving unrelated keys, then refresh runtime provider state.

Replace the provider vector in the global string-keyed config while preserving
unrelated keys, then refresh runtime provider state.
sourceraw docstring

save-toggles!clj

(save-toggles! snapshot)

Persist a {id value} feature-toggle snapshot into the MACHINE store, folding NOTHING else in.

Every flip used to hand save-config! the MERGED config (load-config-raw), which copied the hand-written ~/.vis/config.yml tier and the project's committed vis.yml — filesystem grants included — into state.yml, where the machine tier then WON over the very files they came from: a project's grants became global for every other repository, and a later edit of the hand-written file silently stopped taking effect. Read the machine tier, replace one key, write it back. No-op (and false) when the block is already identical.

Persist a `{id value}` feature-toggle snapshot into the MACHINE store, folding
NOTHING else in.

Every flip used to hand `save-config!` the MERGED config (`load-config-raw`),
which copied the hand-written `~/.vis/config.yml` tier and the project's
committed `vis.yml` — filesystem grants included — into `state.yml`, where the
machine tier then WON over the very files they came from: a project's grants
became global for every other repository, and a later edit of the hand-written
file silently stopped taking effect. Read the machine tier, replace one key,
write it back. No-op (and false) when the block is already identical.
sourceraw docstring

search-textclj

(search-text v)

Universal plain-text projection for full-text search / clipboard / logging. Accepts canonical IR, a markdown string, or anything ->ast can coerce; returns a single concatenated string suitable for FT5 indexing or substring matching.

IR-side rendering: all prose/list/quote/table text collapses to spaces; :code/:c bodies are included verbatim (often the highest-signal text for search). Strings are parsed via markdown->ast so search sees the rendered shape regardless of upstream contract.

Idempotent on parsed input via the markdown->ast shortcut.

Universal plain-text projection for full-text search / clipboard /
logging. Accepts canonical IR, a markdown string, or anything
`->ast` can coerce; returns a single concatenated string suitable
for FT5 indexing or substring matching.

IR-side rendering: all prose/list/quote/table text collapses to spaces;
`:code`/`:c` bodies are included verbatim (often the highest-signal text
for search).
Strings are parsed via `markdown->ast` so search sees the rendered shape
regardless of upstream contract.

Idempotent on parsed input via the `markdown->ast` shortcut.
sourceraw docstring

send!clj

(send! id messages)
(send! id messages opts)
source

session->markdownclj

(session->markdown db-info session-ref)
(session->markdown db-info session-ref opts)

Project a full session as a Markdown document on top of the IR pipeline.

Project a full session as a Markdown document on top of the IR
pipeline.
sourceraw docstring

session-model-ofclj

(session-model-of db-info sid)

The preference for session sid as {:provider :model}, or nil for the router default. Prefers the immediate in-memory value, else the DB. Use on the routing path (engine, gateway).

The preference for session `sid` as `{:provider :model}`, or nil for the
router default. Prefers the immediate in-memory value, else the DB. Use on
the routing path (engine, gateway).
sourceraw docstring

session-model-of-cachedclj

(session-model-of-cached db-info sid)

Like model-of but DISPLAY-oriented: when no pending value exists, a recent DB value is served from a tiny TTL cache so callers can read it every frame without a DB hit.

Like `model-of` but DISPLAY-oriented: when no pending value exists, a recent
DB value is served from a tiny TTL cache so callers can read it every frame
without a DB hit.
sourceraw docstring

session-process-spawn!clj

(session-process-spawn! session-id argv directory)
(session-process-spawn! session-id
                        argv
                        directory
                        {:keys [loopback-port env] :as opts})

THE managed-language launch contract. Resolve session-id atomically, derive its REPL/test policy, merge this call's environment delta, and spawn through [[spawn!]]. Unknown, disposed, or failing sessions are denied before spawn.

Options additionally accept :loopback-port, :env, and every [[spawn!]] option. The returned value is a java.lang.Process.

THE managed-language launch contract. Resolve `session-id` atomically, derive
its REPL/test policy, merge this call's environment delta, and spawn through
[[spawn!]]. Unknown, disposed, or failing sessions are denied before spawn.

Options additionally accept `:loopback-port`, `:env`, and every [[spawn!]]
option. The returned value is a `java.lang.Process`.
sourceraw docstring

set-provider!clj

(set-provider! provider)

Set the single active provider config. Persists to disk, updates in-memory state, rebuilds the global router, and reseats cached session envs. provider is a svar-native provider map {:id :base-url :api-key :models [...]}. Replaces an existing provider with the same :id or appends a new entry.

Set the single active provider config. Persists to disk, updates
in-memory state, rebuilds the global router, and reseats cached
session envs. `provider` is a svar-native provider map
`{:id :base-url :api-key :models [...]}`. Replaces an existing
provider with the same `:id` or appends a new entry.
sourceraw docstring

set-python-binding!clj

(set-python-binding! session sym val)

Bind sym -> val in session's globals.

A FUNCTION becomes a host tool: the name is registered for this session in [[python-host]] and installed by the runtime as a deferred callable, so await tool(...) and gather(tool(...), …) work exactly like the tools the context was built with. A dotted name publishes one declared method through a capability namespace instead of exposing the extension's raw object. Anything else is DATA and crosses as JSON.

Bind `sym` -> `val` in `session`'s globals.

A FUNCTION becomes a host tool: the name is registered for this session in
[[python-host]] and installed by the runtime as a deferred callable, so
`await tool(...)` and `gather(tool(...), …)` work exactly like the tools the
context was built with. A dotted name publishes one declared method through a
capability namespace instead of exposing the extension's raw object. Anything
else is DATA and crosses as JSON.
sourceraw docstring

set-session-model!clj

(set-session-model! db-info sid provider model)
(set-session-model! db-info sid provider model reason)

Set (or clear, with blank model) the PROVIDER + MODEL preference for session sid. Takes effect IMMEDIATELY for reads; the DB write is debounced so rapid cycling coalesces to one write. Returns {:provider :model} (or nil).

reason names why a writer that is NOT the human moved the pick (the engine's :authentication-fallback rescue); it rides the broadcast so a surface can say why the chip changed under the user's hands. nil for a manual pick. An idempotent write neither schedules storage nor announces a change.

Set (or clear, with blank model) the PROVIDER + MODEL preference for session
`sid`. Takes effect IMMEDIATELY for reads; the DB write is debounced so
rapid cycling coalesces to one write. Returns `{:provider :model}` (or nil).

`reason` names why a writer that is NOT the human moved the pick (the engine's
`:authentication-fallback` rescue); it rides the broadcast so a surface can say
why the chip changed under the user's hands. nil for a manual pick. An
idempotent write neither schedules storage nor announces a change.
sourceraw docstring

set-title!clj

(set-title! id title)

Host-driven title change. Resolves the live env (if any) so the in-memory atom + listener fan-out stay in sync; falls back to a plain DB write when no env is live for this session (e.g. vis-agent sessions rename ops).

Host-driven title change. Resolves the live env (if any) so the
in-memory atom + listener fan-out stay in sync; falls back to a
plain DB write when no env is live for this session (e.g.
`vis-agent sessions` rename ops).
sourceraw docstring

shutdown!clj

(shutdown!)

Flush and stop all telemere handlers. Call after the TUI screen stops.

Flush and stop all telemere handlers. Call after the TUI screen
stops.
sourceraw docstring

slash-by-pathclj

(slash-by-path env path)

Return the slash spec whose full path = path, or nil. path is a non-empty vec of names like ["workspace" "apply"]. When multiple specs share the path (per-channel partitioning), returns the first registered.

Return the slash spec whose full path = `path`, or nil. `path` is a
non-empty vec of names like `["workspace" "apply"]`. When
multiple specs share the path (per-channel partitioning), returns
the first registered.
sourceraw docstring

slash-childrenclj

(slash-children env)
(slash-children env parent)

Return the vec of slash specs whose :slash/parent = parent vec. parent defaults to [] (top-level commands).

Return the vec of slash specs whose `:slash/parent` = `parent` vec.
`parent` defaults to `[]` (top-level commands).
sourceraw docstring

slash-dispatchclj

(slash-dispatch env ctx text)

Dispatch slash text against env. ctx carries channel-side knobs:

:channel/id keyword, required (:tui, :cli, ...) :session/id session-soul UUID (optional unless slash declares :slash/requires #{:session}) :workspace/id workspace UUID (optional unless required) :db-info persistence handle (always passed when present in the channel env) :reply! (fn [ir-or-string]) for channels that want an immediate side-effect surface :publish! (fn [event]) bus for cross-channel events

Return shapes documented at the namespace docstring.

Dispatch slash `text` against `env`. `ctx` carries channel-side knobs:

  :channel/id            keyword, required (:tui, :cli, ...)
  :session/id            session-soul UUID (optional unless slash
                         declares `:slash/requires #{:session}`)
  :workspace/id          workspace UUID (optional unless required)
  :db-info               persistence handle (always passed when
                         present in the channel env)
  :reply!                (fn [ir-or-string]) for channels that want
                         an immediate side-effect surface
  :publish!              (fn [event]) bus for cross-channel events

Return shapes documented at the namespace docstring.
sourceraw docstring

slash-paletteclj

(slash-palette channel)
(slash-palette channel extra)

THE canonical typed-/ palette for a channel. Registered slash leaves, channel-native entries, and prompt templates become complete {:name :doc} rows. Registered/channel-native names always win.

THE canonical typed-`/` palette for a channel. Registered slash leaves,
channel-native entries, and prompt templates become complete `{:name :doc}`
rows. Registered/channel-native names always win.
sourceraw docstring

slash-parseclj

(slash-parse text)

Tokenise a slash text into {:path :args :raw} or nil.

This function performs PURE tokenisation. It does NOT consult any slash registry; the engine resolves the longest matching prefix at dispatch time once it has the env. This keeps parse pure and testable in isolation.

Tokenise a slash `text` into `{:path :args :raw}` or nil.

This function performs PURE tokenisation. It does NOT consult any
slash registry; the engine resolves the longest matching prefix at
dispatch time once it has the env. This keeps `parse` pure and
testable in isolation.
sourceraw docstring

stable-prompt-textclj

(stable-prompt-text messages)

Join stable prompt message contents for token budgeting and debug bindings only. Provider sends the original message vector; this is not a send path.

Join stable prompt message contents for token budgeting and debug bindings only.
Provider sends the original message vector; this is not a send path.
sourceraw docstring

state-pathclj

(state-path)

Machine-owned RMW config store ~/.vis/state.yml (YAML). Vis read-modify-writes this exact file — OAuth tokens, TUI-added providers, extension env overrides — so it is kept SEPARATE from the hand-written ~/.vis/config.yml tier: the RMW cycle must never fold (and thus clobber) a user's hand-written YAML.

Machine-owned RMW config store `~/.vis/state.yml` (YAML). Vis read-modify-writes
this exact file — OAuth tokens, TUI-added providers, extension env overrides — so
it is kept SEPARATE from the hand-written `~/.vis/config.yml` tier: the RMW cycle
must never fold (and thus clobber) a user's hand-written YAML.
sourceraw docstring

stop-resource!clj

(stop-resource! session id)

Atomically claim a resource and run its :stop-fn. THE single stop path — the agent tool and the footer both land here, always scoped to session so no session can stop another's resource. A successful stop leaves the claimed generation unregistered. If its callback throws, that generation is restored only when the id is still vacant, preserving both a retry handle and any replacement registered during teardown. Returns a result map.

Atomically claim a resource and run its `:stop-fn`.
THE single stop path — the agent tool and the footer both land here, always
scoped to `session` so no session can stop another's resource. A successful
stop leaves the claimed generation unregistered. If its callback throws, that
generation is restored only when the id is still vacant, preserving both a
retry handle and any replacement registered during teardown. Returns a result
map.
sourceraw docstring

symbolclj

(symbol v)
(symbol v opts)

Build a function symbol entry FROM A CLOJURE VAR.

The 3-arg form (symbol sym-name f opts) is a test-friendly direct constructor: pass the sandbox-visible symbol, the implementation fn, and an opts map whose :doc / :arglists are read directly from opts instead of var meta. Production code uses the var form.

The var supplies :symbol (var name), :fn (the var's value), :doc and :arglists (read from var metadata - i.e. the underlying defn's docstring + arglists). Pass it as #'my-tool.

Observed tools return canonical internal envelope maps. Declare :activity beside every observed binding: {:headline "Read file" :show-start false :render callback}. Activity is for people: use understandable sentence-case English, not identifiers or all-caps sentences. Quick reads and patches use :show-start false to show only the end result; slow operations keep the default true to show running progress. This hides presentation, never internal timing, failure or cancellation tracking. The optional callback receives invocation details and a bounded, redacted public result, and returns a canonical Activity presentation. Tools can instead call publish-activity! while running. No generic result presentation is generated; the engine owns identity, state, timing, errors and file-change evidence.

Raw helpers pass :raw? true and return plain values directly, with no envelope enforcement, channel sink, or tool metadata.

Optional opts: :symbol - override the Python sandbox name (default: var name). :doc-fn - compute doc lazily from (sym v) when the var lacks a docstring (third-party vars only). :raw? - true for plain composable helpers. :tag - REQUIRED :observation | :mutation for observed tools (unless :raw? true). :params - options-dict key vocabulary [{:name "paths" :required? true} {:name "ranges"}], rendered by doc(name). REQUIRED of every tool whose call ends in an options dict — a **kwargs signature states nothing a caller can act on. :before-fn :after-fn :on-error-fn :ticker-fn

Observed tool functions return canonical internal envelope maps. The wrapper records the envelope, then returns only its payload to Python; failure envelopes are converted into thrown ex-info so Python reports normal errors.

:doc and :arglists ALWAYS come from var metadata — the previous test-only (symbol sym-name f opts) 3-arg form is RETIRED. Tests that want to register an inline fn must defn it first and pass #'the-fn.

See docs/src/extensions/hooks.md for hook semantics.

Build a function symbol entry FROM A CLOJURE VAR.

The 3-arg form `(symbol sym-name f opts)` is a test-friendly direct
constructor: pass the sandbox-visible symbol, the implementation fn, and
an opts map whose `:doc` / `:arglists` are read directly from opts
instead of var meta. Production code uses the var form.

The var supplies `:symbol` (var name), `:fn` (the var's value), `:doc` and
`:arglists` (read from var metadata - i.e. the underlying defn's
docstring + arglists). Pass it as `#'my-tool`.

Observed tools return canonical internal envelope maps. Declare `:activity`
beside every observed binding: `{:headline "Read file" :show-start false :render callback}`.
Activity is for people: use understandable sentence-case English, not identifiers
or all-caps sentences. Quick reads and patches use `:show-start false` to show only
the end result; slow operations keep the default true to show running progress.
This hides presentation, never internal timing, failure or cancellation tracking. The
optional callback receives invocation details and a bounded, redacted public
result, and returns a canonical Activity presentation. Tools can instead call
`publish-activity!` while running. No generic result presentation is generated;
the engine owns identity, state, timing, errors and file-change evidence.

Raw helpers pass `:raw? true` and return plain values directly, with no
envelope enforcement, channel sink, or tool metadata.

Optional opts:
  :symbol      - override the Python sandbox name (default: var name).
  :doc-fn      - compute doc lazily from `(sym v)` when the var
                 lacks a docstring (third-party vars only).
  :raw?        - true for plain composable helpers.
  :tag         - REQUIRED `:observation | :mutation` for observed
                 tools (unless `:raw? true`).
  :params      - options-dict key vocabulary `[{:name "paths" :required? true}
                 {:name "ranges"}]`, rendered by `doc(name)`. REQUIRED of every
                 tool whose call ends in an options dict — a `**kwargs`
                 signature states nothing a caller can act on.
  :before-fn :after-fn :on-error-fn :ticker-fn

Observed tool functions return canonical internal envelope maps. The
wrapper records the envelope, then returns only its payload to Python; failure
envelopes are converted into thrown ex-info so Python reports normal errors.

`:doc` and `:arglists` ALWAYS come from var metadata — the previous
test-only `(symbol sym-name f opts)` 3-arg form is RETIRED. Tests
that want to register an inline fn must `defn` it first and pass
`#'the-fn`.

See `docs/src/extensions/hooks.md` for hook semantics.
sourceraw docstring

sync-active-extension-symbols!clj

(sync-active-extension-symbols! environment)
(sync-active-extension-symbols! environment active-extensions)

Make the Python sandbox's callable globals match active extension state.

install-extension! keeps every extension row in :extensions, but only active extensions contribute callable symbols. Called after per-env installation and again at turn start so :ext/activation-fn changes become real tool availability, not just prompt visibility.

The Python sandbox is FLAT globals (no namespaces/aliases/macros): active extensions putMember their symbols straight into the top scope; deactivated extensions have theirs removed (putMember nil). Symbol names are snake-ified by env/set-python-binding!.

Make the Python sandbox's callable globals match active extension state.

`install-extension!` keeps every extension row in `:extensions`, but only
active extensions contribute callable symbols. Called after per-env
installation and again at turn start so `:ext/activation-fn` changes become
real tool availability, not just prompt visibility.

The Python sandbox is FLAT globals (no namespaces/aliases/macros): active
extensions putMember their symbols straight into the top scope; deactivated
extensions have theirs removed (putMember nil). Symbol names are snake-ified
by env/set-python-binding!.
sourceraw docstring

system-var-sym?clj

(system-var-sym? sym)
source

SYSTEM_VAR_NAMESclj

Host-owned globals refreshed with the standing context and hidden from user live vars.

Host-owned globals refreshed with the standing context and hidden from user live vars.
sourceraw docstring

test-python-extensions!clj

(test-python-extensions!)
(test-python-extensions! {:keys [dirs sys-path]})

Discover and run every Python test (test_*.py / *_test.py) across the extension dirs (default: ~/.vis/extensions and <cwd>/.vis/extensions), each in its own TRUSTED session driving real pytest, which the sandbox installs on first use. Tests import the extension's own package through the sys.path sugar, exactly like extension.py does.

Returns {:files n :ok? bool :passed n :failed n :errored n :skipped n :tests [{:file :nodeid :outcome :message}] :results [{:file :ok? :tests …}]}. Counts are DERIVED from :tests (the flat per-test list) — the single source of truth. Never throws: a file that blows up at import is one :errored result, not a crash.

:sys-path adds extra import roots (the project's own declared src layout) below each test's own dirs, so a test that imports the package under test resolves it the way the project's packaging metadata says it should.

Discover and run every Python test (`test_*.py` / `*_test.py`) across the
extension dirs (default: `~/.vis/extensions` and `<cwd>/.vis/extensions`),
each in its own TRUSTED session driving real `pytest`, which the sandbox
installs on first use. Tests import the extension's own package through the
`sys.path` sugar,
exactly like `extension.py` does.

Returns `{:files n :ok? bool :passed n :failed n :errored n :skipped n
:tests [{:file :nodeid :outcome :message}] :results [{:file :ok? :tests …}]}`.
Counts are DERIVED from `:tests` (the flat per-test list) — the single source
of truth. Never throws: a file that blows up at import is one `:errored`
result, not a crash.

`:sys-path` adds extra import roots (the project's own declared `src` layout)
below each test's own dirs, so a test that imports the package under test
resolves it the way the project's packaging metadata says it should.
sourceraw docstring

themeclj

(theme id)

Return registered theme by id (string or keyword). Unknown ids fall back to default-theme.

Return registered theme by id (string or keyword). Unknown ids fall back to
`default-theme`.
sourceraw docstring

theme->web-css-varsclj

(theme->web-css-vars {:keys [palette settings]})

CSS custom-property map ("--bg" -> "#rrggbb") for a theme map - the palette-named tokens, the derived bg/fg mixes, and the luminance-delta-normalized border hairlines.

CSS custom-property map ("--bg" -> "#rrggbb") for a theme map -
the palette-named tokens, the derived bg/fg mixes, and the
luminance-delta-normalized border hairlines.
sourceraw docstring

theme-registryclj

(theme-registry)

Return current immutable theme registry map.

Return current immutable theme registry map.
sourceraw docstring

themesclj

source

toggle-add-listener!clj

(toggle-add-listener! f)

Register a no-arg-or-event listener fn. Returns a dispose! thunk the caller invokes when their consumer goes away (channel close, extension reload, ...).

Register a no-arg-or-event listener fn. Returns a `dispose!` thunk
the caller invokes when their consumer goes away (channel close,
extension reload, ...).
sourceraw docstring

toggle-choicesclj

(toggle-choices id)

Vec of legal choices for an :enum toggle. Empty when id is unregistered or registered as :boolean.

Vec of legal choices for an `:enum` toggle. Empty when `id` is
unregistered or registered as `:boolean`.
sourceraw docstring

toggle-cycle-value!clj

(toggle-cycle-value! id)

Advance an :enum toggle one step through its registered :choices. Wraps at the end. Throws on boolean toggles.

Advance an `:enum` toggle one step through its registered
`:choices`. Wraps at the end. Throws on boolean toggles.
sourceraw docstring

toggle-enabled?clj

(toggle-enabled? id)

Boolean cast of (value-of id). Fail-closed: returns false when id is not registered. Hot-path — one atom deref.

Boolean cast of `(value-of id)`. Fail-closed: returns `false` when `id` is not
registered. Hot-path — one atom deref.
sourceraw docstring

toggle-reset-to-default!clj

(toggle-reset-to-default! id)

Drop the user override for id so resolution falls back to the registered default. Notifies listeners when the effective value changes.

Drop the user override for `id` so resolution falls back to the
registered default. Notifies listeners when the effective value
changes.
sourceraw docstring

toggle-set-enabled!clj

(toggle-set-enabled! id value)

Boolean alias of set-value! for the TUI dialog — keeps the common toggle-flip call sites readable. Refuses :enum toggles so an accidental boolean-flip on a multi-value toggle surfaces loudly; use cycle-value! / set-value! for those.

Boolean alias of `set-value!` for the TUI dialog — keeps the
common toggle-flip call sites readable. Refuses `:enum` toggles
so an accidental boolean-flip on a multi-value toggle surfaces
loudly; use `cycle-value!` / `set-value!` for those.
sourceraw docstring

toggle-set-value!clj

(toggle-set-value! id value)

Set id to value and notify listeners. Returns the new value. Validation matches the registered :type: :boolean — must already BE a boolean; anything else throws, so a truthy string can never mean its own opposite. set-enabled! casts, coerce-config-value and wire-value parse. :enum — must be one of :choices; otherwise throws :vis.toggles/invalid-value so the bug surfaces at the call site instead of later in render.

Set `id` to `value` and notify listeners. Returns the new value.
Validation matches the registered `:type`:
  `:boolean` — must already BE a boolean; anything else throws, so a
               truthy string can never mean its own opposite. `set-enabled!`
               casts, `coerce-config-value` and `wire-value` parse.
  `:enum`    — must be one of `:choices`; otherwise throws
                `:vis.toggles/invalid-value` so the bug surfaces
                at the call site instead of later in render.
sourceraw docstring

toggle-specclj

(toggle-spec id)

Lookup the registered spec for id, or nil.

Lookup the registered spec for `id`, or nil.
sourceraw docstring

toggle-typeclj

(toggle-type id)

:boolean / :enum / nil for unknown.

`:boolean` / `:enum` / nil for unknown.
sourceraw docstring

toggle-valueclj

(toggle-value id)

Resolve the live value for id. Lookup order:

  1. live override in state,
  2. registered default,
  3. nil if the toggle isn't registered.

Returns the raw value (boolean for :boolean toggles, any value from :choices for :enum toggles). enabled? is the boolean-cast convenience for the common boolean path.

Resolve the live value for `id`. Lookup order:
  1. live override in `state`,
  2. registered default,
  3. `nil` if the toggle isn't registered.

Returns the raw value (boolean for `:boolean` toggles, any value
from `:choices` for `:enum` toggles). `enabled?` is the
boolean-cast convenience for the common boolean path.
sourceraw docstring

toggles-for-channelclj

(toggles-for-channel channel)

visible-toggles further scoped to channel via toggle-for-channel?. Channels render THIS instead of visible-toggles so each Settings UI only shows controls it actually honours.

`visible-toggles` further scoped to `channel` via `toggle-for-channel?`.
Channels render THIS instead of `visible-toggles` so each Settings UI
only shows controls it actually honours.
sourceraw docstring

toggles-hydrate-from-config!clj

(toggles-hydrate-from-config! config-map)

Bulk-apply values from the string-keyed YAML toggles map. Keyword-keyed internal maps remain accepted for callers that do not originate at YAML.

Bulk-apply values from the string-keyed YAML `toggles` map. Keyword-keyed
internal maps remain accepted for callers that do not originate at YAML.
sourceraw docstring

toggles-snapshotclj

(toggles-snapshot)

Return a map {id value} of EVERY persistable toggle's effective value, intended for serialisation. Skips toggles whose :persist? is false. Boolean toggles are coerced to boolean; enum toggles surface their raw choice value. Orphans from a previously-installed extension are dropped. Keys are SORTED so the serialised block is stable and diff-friendly, never a hash jumble.

Return a map `{id value}` of EVERY persistable toggle's effective
value, intended for serialisation. Skips toggles whose
`:persist?` is false. Boolean toggles are coerced to boolean;
enum toggles surface their raw choice value. Orphans from a
previously-installed extension are dropped. Keys are SORTED so the
serialised block is stable and diff-friendly, never a hash jumble.
sourceraw docstring

tty-inclj

source

tty-outclj

source

turn!clj

(turn! environment messages)
(turn! environment messages opts)

Runs one session turn on an RLM environment using iterative LLM code evaluation.

Params: environment - RLM environment from create-environment. messages - Vector of message maps. Always a vector, e.g.: [(svar/user <prompt-text>)] [(svar/user <prompt-text> (svar/image <b64> <mime-type>))] opts - Map, optional:

  • :spec - Output spec for structured answers.
  • :model - Override config's default model.
  • :max-context-tokens - Token budget for context.
  • :debug? - Enable verbose debug logging (default: false). Logs iteration details, code evaluation, LLM responses at :debug level with :rlm-phase context.
  • :reasoning-default - Optional base reasoning effort for reasoning-capable models. Accepts :low/:medium/:high or low/medium/high strings. Adaptive escalation still applies.
  • :reasoning-effort - Exact provider-native effort string, high or max. Catalog-gated and threaded unchanged through every iteration.
  • :extra-body - Optional provider-specific request-body params merged into the upstream LLM call after auto max_tokens + reasoning translation.

Returns: Map with:

  • :trace - Vector of iteration trace entries, each containing: {:iteration N :response <llm-response-text> :blocks [{:id 0 :code <code-str> :stdout <printed-text> :error nil :envelope {:started-at-ms 10 :finished-at-ms 15 ...}} ...]}
  • :iteration-count - Number of iterations used.
  • :duration-ms - Turn duration in milliseconds.
  • :tokens - Token usage map {"input" N "output" N "total" N} (canonical string keys).
  • :cost - Cost map {"input_cost" N "output_cost" N "total_cost" N} (canonical string keys).
  • :confidence - Confidence level (:high/:medium/:low) from final iteration.
  • :reasoning - String summary of how the answer was derived (from LLM's FINAL call).
  • :status - Only present on failure (:error or :cancelled).
Runs one session turn on an RLM environment using iterative LLM code evaluation.

 Params:
 `environment` - RLM environment from create-environment.
 `messages` - Vector of message maps. Always a vector, e.g.:
              [(svar/user <prompt-text>)]
              [(svar/user <prompt-text> (svar/image <b64> <mime-type>))]
`opts` - Map, optional:
  - :spec - Output spec for structured answers.
  - :model - Override config's default model.
   - :max-context-tokens - Token budget for context.
   - :debug? - Enable verbose debug logging (default: false). Logs iteration details,
     code evaluation, LLM responses at :debug level with :rlm-phase context.
   - :reasoning-default - Optional base reasoning effort for reasoning-capable models.
     Accepts :low/:medium/:high or low/medium/high strings. Adaptive escalation still applies.
   - :reasoning-effort - Exact provider-native effort string, `high` or `max`.
     Catalog-gated and threaded unchanged through every iteration.
   - :extra-body - Optional provider-specific request-body params merged into the
     upstream LLM call after auto max_tokens + reasoning translation.

 Returns:
Map with:
   - :trace - Vector of iteration trace entries, each containing:
       {:iteration N
        :response <llm-response-text>
        :blocks [{:id 0 :code <code-str> :stdout <printed-text> :error nil
                  :envelope {:started-at-ms 10 :finished-at-ms 15 ...}}
                    ...]}
  - :iteration-count - Number of iterations used.
  - :duration-ms - Turn duration in milliseconds.
  - :tokens - Token usage map {"input" N "output" N "total" N} (canonical string keys).
  - :cost - Cost map {"input_cost" N "output_cost" N "total_cost" N} (canonical string keys).
  - :confidence - Confidence level (:high/:medium/:low) from final iteration.
   - :reasoning - String summary of how the answer was derived (from LLM's FINAL call).
   - :status - Only present on failure (`:error` or `:cancelled`).
sourceraw docstring

unknown-flagsclj

(unknown-flags arg-specs raw-args)

Return a vector of --flag tokens in raw-args that are NOT declared in arg-specs. Walks the args the same way parse-args does so that a string-typed flag's VALUE (e.g. bar in --out bar) is never misclassified as an unknown flag. Boolean flags don't consume their next token. Universal --help / -h are always considered known.

Used by dispatch! to refuse unknown flags and surface the list of accepted flags via render-command. Pure; no side effects.

Unknown flags are reported only by their leading token; we don't know whether the user intended them to take a value, so the walker conservatively advances by one token after each unknown.

Return a vector of `--flag` tokens in `raw-args` that are NOT declared
in `arg-specs`. Walks the args the same way `parse-args` does so that
a string-typed flag's VALUE (e.g. `bar` in `--out bar`) is never
misclassified as an unknown flag. Boolean flags don't consume their
next token. Universal `--help` / `-h` are always considered known.

Used by `dispatch!` to refuse unknown flags and surface the list of
accepted flags via `render-command`. Pure; no side effects.

Unknown flags are reported only by their leading token; we don't
know whether the user intended them to take a value, so the walker
conservatively advances by one token after each unknown.
sourceraw docstring

unregister-op-hooks-for-owner!clj

(unregister-op-hooks-for-owner! owner)

Remove EVERY op-hook registered by owner (all ops + phases). Driven by deregister-extension! so an extension's hooks die with it; also callable directly to dynamically tear an extension's hooks down.

Remove EVERY op-hook registered by `owner` (all ops + phases). Driven by
`deregister-extension!` so an extension's hooks die with it; also callable
directly to dynamically tear an extension's hooks down.
sourceraw docstring

unregister-resource!clj

(unregister-resource! session id)

Drop the resource generation current when this call began from session (does NOT run its stop-fn — caller decides). A concurrent replacement is never removed. Returns true only when the captured generation was removed.

Drop the resource generation current when this call began from `session`
(does NOT run its stop-fn — caller decides). A concurrent replacement is never
removed. Returns true only when the captured generation was removed.
sourceraw docstring

unregister-theme!clj

(unregister-theme! id)

Remove a theme id. Built-ins reset to their built-in value instead of being removed, so the registry always keeps light and dark available.

Remove a theme id. Built-ins reset to their built-in value instead of being
removed, so the registry always keeps light and dark available.
sourceraw docstring

unregister-themes!clj

(unregister-themes! ids)
source

unwatch-notifications!clj

(unwatch-notifications! key)

Remove the watcher registered under key. Returns true when one was actually removed.

Remove the watcher registered under `key`. Returns true when one
was actually removed.
sourceraw docstring

update-config-provider!clj

(update-config-provider! provider-id f)
(update-config-provider! provider-id f source)

Apply f to one persisted provider and save the resulting fleet.

Apply `f` to one persisted provider and save the resulting fleet.
sourceraw docstring

update-machine-config!clj

(update-machine-config! f)
(update-machine-config! f source)

Read-modify-write the machine store ~/.vis/state.yml under a lock: apply f to the raw string-keyed map (an absent store arrives as {}) and persist the result through save-config!.

THE write pattern for everything Vis persists about itself. Every writer here rewrites the WHOLE map, so the read and the write have to be ONE critical section: a provider added while a toggle flipped used to write back the toggle block the other writer had just replaced. The file was never corrupt — the update was simply lost, silently, and the loser only found out much later.

The lock lives in a sibling state.yml.lock because the store itself is REPLACED by an atomic move, and a lock taken on a replaced inode guards nothing.

Returns the written map, or nil when f answered nil or changed nothing (no write, no provider-selected event). A lock the filesystem refuses (a network mount) degrades to the plain read-modify-write rather than to no write at all.

Read-modify-write the machine store `~/.vis/state.yml` under a lock: apply `f`
to the raw string-keyed map (an absent store arrives as `{}`) and persist the
result through `save-config!`.

THE write pattern for everything Vis persists about itself. Every writer here
rewrites the WHOLE map, so the read and the write have to be ONE critical
section: a provider added while a toggle flipped used to write back the toggle
block the other writer had just replaced. The file was never corrupt — the
update was simply lost, silently, and the loser only found out much later.

The lock lives in a sibling `state.yml.lock` because the store itself is
REPLACED by an atomic move, and a lock taken on a replaced inode guards
nothing.

Returns the written map, or nil when `f` answered nil or changed nothing (no
write, no provider-selected event). A lock the filesystem refuses (a network
mount) degrades to the plain read-modify-write rather than to no write at all.
sourceraw docstring

update-resource!clj

(update-resource! session id patch)

Patch the DATA of the resource generation current when this call began (e.g. flip :status, refresh :detail). No-op if unknown or if that generation was replaced while the patch was being prepared. Returns the updated DATA map or nil.

Patch the DATA of the resource generation current when this call began (e.g.
flip `:status`, refresh `:detail`). No-op if unknown or if that generation was
replaced while the patch was being prepared. Returns the updated DATA map or
nil.
sourceraw docstring

utf8clj

(utf8 s)

s as UTF-8 bytes — the one charset every vis wire format names.

`s` as UTF-8 bytes — the one charset every vis wire format names.
sourceraw docstring

validate-argsclj

(validate-args arg-specs parsed)

Validate parsed args against spec. Returns nil on success, or an error string describing the missing required arguments.

Validate parsed args against spec. Returns nil on success, or an
error string describing the missing required arguments.
sourceraw docstring

valueclj

(value v)
(value v opts-or-val)
(value sym-name val opts)

Build a value symbol entry FROM A CLOJURE VAR - a plain constant/data binding.

The var supplies :symbol (var name), :val (the var's value, unless :val is provided in opts to override - used by macro-shim entries), and :doc (from var metadata, i.e. the defn's docstring).

(def ^{:doc "Maximum retry attempts."} max-retries 3) (vis/value #'max-retries)

Opts: :symbol - override the Python sandbox name (default: var name). :val - explicit value override (rare; for macro shims that bind a marker map instead of the var's own value).

Build a value symbol entry FROM A CLOJURE VAR - a plain constant/data binding.

The var supplies `:symbol` (var name), `:val` (the var's value, unless `:val`
is provided in opts to override - used by macro-shim entries), and `:doc`
(from var metadata, i.e. the defn's docstring).

(def ^{:doc "Maximum retry attempts."} max-retries 3)
(vis/value #'max-retries)

Opts:
  :symbol - override the Python sandbox name (default: var name).
  :val - explicit value override (rare; for macro shims that bind a
         marker map instead of the var's own value).
sourceraw docstring

verbosity-configurable?clj

(verbosity-configurable? resolved-model)

True when a model accepts a caller-selected answer verbosity.

Also svar's call: :verbosity-style is stamped from the wire, so every provider on the OpenAI Responses endpoint (Codex AND GitHub Copilot's GPT tier) gets the knob and nothing else does. Never test a provider id here.

True when a model accepts a caller-selected answer verbosity.

Also svar's call: `:verbosity-style` is stamped from the wire, so every
provider on the OpenAI Responses endpoint (Codex AND GitHub Copilot's GPT
tier) gets the knob and nothing else does. Never test a provider id here.
sourceraw docstring

view-action!clj

source

virtual-threads-available?clj

(virtual-threads-available?)

True when this JVM exposes Java virtual-thread APIs. Reflection keeps source compatible with older runtimes.

True when this JVM exposes Java virtual-thread APIs. Reflection keeps
source compatible with older runtimes.
sourceraw docstring

vis-darkclj

Default Vis dark theme.

Default Vis dark theme.
sourceraw docstring

vis-lightclj

Default Vis light theme.

Default Vis light theme.
sourceraw docstring

visible-togglesclj

(visible-toggles)

registered-toggles filtered to what settings UIs should SHOW — provider-specific knobs declare a :visible-fn so a knob only appears when the provider that owns it is actually configured, and :settings? false toggles (e.g. reasoning-effort and verbosity, which have their own Ctrl+R / Ctrl+X controls) stay out of the Settings dialog entirely. State ops always work on the FULL registry; visibility is a presentation concern only.

`registered-toggles` filtered to what settings UIs should SHOW —
provider-specific knobs declare a `:visible-fn` so a knob only appears when
the provider that owns it is actually configured, and `:settings? false`
toggles (e.g. reasoning-effort and verbosity, which have their own Ctrl+R /
Ctrl+X controls) stay out of the Settings dialog entirely.
State ops always work on the FULL registry; visibility is a presentation
concern only.
sourceraw docstring

watch-notifications!clj

(watch-notifications! key f)

Register a watcher under key. The fn f is called with the full active-notifications vec on every push / dismiss / clear. Replacing an existing watcher under the same key is fine - typical pattern is (watch! :tui-screen render-bump).

Watchers run synchronously on the mutating thread, AFTER the atom swap. They MUST be cheap (microseconds) - anything heavier should bounce work onto a future.

Register a watcher under `key`. The fn `f` is called with the
full active-notifications vec on every push / dismiss / clear.
Replacing an existing watcher under the same key is fine -
typical pattern is `(watch! :tui-screen render-bump)`.

Watchers run synchronously on the mutating thread, AFTER the
atom swap. They MUST be cheap (microseconds) - anything heavier
should bounce work onto a future.
sourceraw docstring

web-css-rootclj

(web-css-root theme-or-id)

A :root{...} CSS block for a theme id (or theme map): every shared var from theme->web-css-vars plus color-scheme, ready to serve AFTER the static stylesheet so it overrides the baked-in defaults.

A `:root{...}` CSS block for a theme id (or theme map): every shared
var from `theme->web-css-vars` plus `color-scheme`, ready to serve
AFTER the static stylesheet so it overrides the baked-in defaults.
sourceraw docstring

wire->engineclj

(wire->engine x)

Recursively convert decoded wire data into the engine's keyword-keyed shape — the mirror of [[->wire]]. Only KEYS are converted (via [[engine-key]]); values are data and are never re-typed.

Recursively convert decoded wire data into the engine's keyword-keyed shape —
the mirror of [[->wire]]. Only KEYS are converted (via [[engine-key]]); values
are data and are never re-typed.
sourceraw docstring

wire->wireclj

(wire->wire x)

Recursively convert an engine value into JSON-encodable data.

Recursively convert an engine value into JSON-encodable data.
sourceraw docstring

wire-canonicalclj

(wire-canonical x)

THE canonical gateway value shape — snake_case STRING map keys, exactly what a remote client holds after parse-jsonjson-str. In-process and remote consumers therefore read the same role-labelled messages and typed content blocks.

Invariant: (canonical x) equals (parse-json (json-str x)).

THE canonical gateway value shape — snake_case STRING map keys, exactly
what a remote client holds after `parse-json` ∘ `json-str`. In-process and
remote consumers therefore read the same role-labelled messages and typed
content blocks.

Invariant: `(canonical x)` equals `(parse-json (json-str x))`.
sourceraw docstring

wire-json-prettyclj

(wire-json-pretty x)

Pretty-print canonical wire JSON for human-facing views.

Pretty-print canonical wire JSON for human-facing views.
sourceraw docstring

wire-json-strclj

(wire-json-str x)

Encode any engine value as a JSON string via [[->wire]].

Encode any engine value as a JSON string via [[->wire]].
sourceraw docstring

wire-keyclj

(wire-key k)

Keyword/symbol map key -> snake_case string. A boolean-style foo? key becomes is_foo (already-is- prefixed keys just drop the ?). String keys (fact keys, scope strings, file paths) pass VERBATIM - rewriting them could corrupt user data that legitimately contains hyphens. ANY other key (the number/boolean/nil keys a decoded JSON or Python value can carry into a tool result) is rendered to its JSON key spelling: JSON has no non-string keys, and leaving one unrendered makes the whole event unencodable - which kills the transport, not just the field.

Keyword/symbol map key -> snake_case string. A boolean-style `foo?` key
becomes `is_foo` (already-`is-` prefixed keys just drop the `?`). String
keys (fact keys, scope strings, file paths) pass VERBATIM - rewriting
them could corrupt user data that legitimately contains hyphens. ANY
other key (the number/boolean/nil keys a decoded JSON or Python value can
carry into a tool result) is rendered to its JSON key spelling: JSON has
no non-string keys, and leaving one unrendered makes the whole event
unencodable - which kills the transport, not just the field.
sourceraw docstring

with-live-view!clj

source

worker-futureclj

(worker-future f)
(worker-future name f)
(worker-future name f {:keys [platform?]})

Run f on a cancellable worker Future. Uses a virtual thread when the JVM supports it, otherwise falls back to a named daemon platform thread.

Pass {:platform? true} for work that can pin a virtual-thread carrier in native or uninterruptible code. A platform worker costs one thread but cannot starve the virtual-thread scheduler that runs ordinary lightweight work.

The returned value implements java.util.concurrent.Future plus Clojure deref/realized? protocols so legacy future call sites can migrate without losing timeout/cancellation behavior.

Run `f` on a cancellable worker Future. Uses a virtual thread when the JVM
supports it, otherwise falls back to a named daemon platform thread.

Pass `{:platform? true}` for work that can pin a virtual-thread carrier in
native or uninterruptible code. A platform worker costs one thread but cannot
starve the virtual-thread scheduler that runs ordinary lightweight work.

The returned value implements java.util.concurrent.Future plus Clojure
deref/realized? protocols so legacy `future` call sites can migrate without
losing timeout/cancellation behavior.
sourceraw docstring

worker-runtimeclj

(worker-runtime)

Runtime probe for worker execution. :worker-helper is stable metadata for diagnostics; :virtual-threads? reports whether new worker tasks will use Java virtual threads.

Runtime probe for worker execution. `:worker-helper` is stable metadata for
diagnostics; `:virtual-threads?` reports whether new worker tasks will use
Java virtual threads.
sourceraw docstring

workspace-abandon!clj

(workspace-abandon! db-info {:keys [workspace-id reason]})

Transition a workspace to :discarded and release the backend-owned clones it holds: its primary clone plus every private per-root draft clone.

Transition a workspace to :discarded and release the backend-owned clones it
holds: its primary clone plus every private per-root draft clone.
sourceraw docstring

workspace-apply!clj

(workspace-apply! db-info {:keys [workspace-id]})

Land a draft's changes into their real roots: the primary clone into :repo-root, plus every extra root minted with the copy-and-apply draft policy into its own trunk. copy-only / not-allowed roots never land.

Land a draft's changes into their real roots: the primary clone into
`:repo-root`, plus every extra root minted with the `copy-and-apply` draft
policy into its own trunk. `copy-only` / `not-allowed` roots never land.
sourceraw docstring

workspace-capability-matrixclj

(workspace-capability-matrix workspace-or-root)

Availability of each draft backend for workspace-or-root, checked against the real derived storage location rather than assuming source and store share a filesystem: [{:backend :worktree …} {:backend :rift …}], each with :available? and, when unavailable, :reason/:details. A diagnostics surface — draft-backend-for is the selection.

Availability of each draft backend for `workspace-or-root`, checked against
the real derived storage location rather than assuming source and store share
a filesystem: `[{:backend :worktree …} {:backend :rift …}]`, each with
`:available?` and, when unavailable, `:reason`/`:details`. A diagnostics
surface — `draft-backend-for` is the selection.
sourceraw docstring

workspace-change-root!clj

(workspace-change-root! db-info session-state-id path)

Repoint session-state-id's primary workspace root to path. Refuses while the session is in an isolated workspace.

Repoint `session-state-id`'s primary workspace root to `path`. Refuses while
the session is in an isolated workspace.
sourceraw docstring

workspace-create!clj

(workspace-create! db-info
                   {:keys [session-state-id label from clean?
                           filesystem-roots]})

Create an isolated DRAFT with the backend draft-backend-for selects for the fork parent — a linked Git worktree on a fresh vis/<label> branch, or a Rift copy-on-write clone — and pin it to :session-state-id. Core never silently falls back to a shared root: with drafts switched off this throws :workspace/drafts-disabled, with no capable backend :workspace/capability-unavailable.

Pass :from <parent-workspace> to clone that workspace's :root and inherit its :repo-root; otherwise the parent is the user's real cwd (trunk). apply! copies files back to repo-root; approve! merges into that repository's default branch, which may have a different checkout.

By default the draft carries the parent's pending work: a Rift clone copies it, a worktree checks HEAD out and replays the uncommitted diff plus untracked files into it. :clean? true hands back the committed state instead — Rift resets the clone (recording the omissions in its marker), a worktree simply skips the replay. The baseline is captured after that seeding so it is not read as an agent edit. A project that is not Git-managed has no committed state to seed from, so a clean draft is refused there before anything is cloned.

Create an isolated DRAFT with the backend `draft-backend-for` selects for the
fork parent — a linked Git worktree on a fresh `vis/<label>` branch, or a Rift
copy-on-write clone — and pin it to `:session-state-id`. Core never silently
falls back to a shared root: with drafts switched off this throws
`:workspace/drafts-disabled`, with no capable backend
`:workspace/capability-unavailable`.

Pass `:from <parent-workspace>` to clone that workspace's `:root` and inherit
its `:repo-root`; otherwise the parent is the user's real cwd (trunk).
`apply!` copies files back to repo-root; `approve!` merges into that
repository's default branch, which may have a different checkout.

By default the draft carries the parent's pending work: a Rift clone copies
it, a worktree checks HEAD out and replays the uncommitted diff plus untracked
files into it. `:clean? true` hands back the committed state instead — Rift
resets the clone (recording the omissions in its marker), a worktree simply
skips the replay. The baseline is captured after that seeding so it is not
read as an agent edit. A project that is not Git-managed has no committed
state to seed from, so a clean draft is refused there before anything is
cloned.
sourceraw docstring

workspace-create-dir!clj

(workspace-create-dir! parent name)

Create a single child directory name under existing directory parent. Returns the canonical path of the (possibly already-existing) child. Throws when parent is not a directory or name is not a single safe path segment. name may not contain a separator, be blank, or be ./...

Create a single child directory `name` under existing directory `parent`.
Returns the canonical path of the (possibly already-existing) child. Throws
when `parent` is not a directory or `name` is not a single safe path segment.
`name` may not contain a separator, be blank, or be `.`/`..`.
sourceraw docstring

workspace-create-trunk-at!clj

(workspace-create-trunk-at! db-info root)

Mint a TRUNK workspace rooted at root (an arbitrary directory), not pinned to any session. Lets a channel open a session under a directory OTHER than the one vis was launched from — a tab in another project. Returns the workspace row (with :id) to pass as :workspace-id when creating the session.

Mint a TRUNK workspace rooted at `root` (an arbitrary directory), not
pinned to any session. Lets a channel open a session under a directory
OTHER than the one vis was launched from — a tab in another project.
Returns the workspace row (with `:id`) to pass as `:workspace-id` when
creating the session.
sourceraw docstring

workspace-cwdclj

(workspace-cwd)

Resolve the current workspace cwd. In production the channel wrapper binds *workspace-root* per turn, so the process-cwd fallback only fires from REPL / test / one-off CLI paths that have no session context.

Resolve the current workspace cwd. In production the channel
wrapper binds `*workspace-root*` per turn, so the process-cwd
fallback only fires from REPL / test / one-off CLI paths that have
no session context.
sourceraw docstring

workspace-display-labelclj

(workspace-display-label workspace)
(workspace-display-label db-info workspace session)

Human-facing label for workspace. Order: explicit :label → pinned session title → clone name (:branch) → id prefix.

Human-facing label for `workspace`. Order: explicit `:label` →
pinned session title → clone name (`:branch`) → id prefix.
sourceraw docstring

workspace-ensure-workspace!clj

(workspace-ensure-workspace! db-info {:keys [session-state-id]})

Find-or-create the session's workspace. The DEFAULT is TRUNK — the user's real cwd (no clone). Resume returns whatever workspace the session was pinned to. Idempotent per session-state.

Find-or-create the session's workspace. The DEFAULT is TRUNK — the
user's real cwd (no clone). Resume returns whatever workspace the session was
pinned to. Idempotent per session-state.
sourceraw docstring

workspace-focus!clj

(workspace-focus! db-info workspace-id)

Stamp last_focused_at_ms and upsert the per-repo repo_focus pointer. Returns the updated workspace record.

Stamp `last_focused_at_ms` and upsert the per-repo `repo_focus`
pointer. Returns the updated workspace record.
sourceraw docstring

workspace-for-sessionclj

(workspace-for-session db-info session-state-id)

Workspace pinned to session-state-id, or nil.

Workspace pinned to `session-state-id`, or nil.
sourceraw docstring

workspace-getclj

(workspace-get db-info workspace-id)

Return the workspace with workspace-id, or nil.

Return the workspace with `workspace-id`, or nil.
sourceraw docstring

workspace-isolation-supported?clj

(workspace-isolation-supported?)
(workspace-isolation-supported? root)

True when the current root can create full draft workspaces under the current draft_backend setting.

True when the current root can create full draft workspaces under the
current `draft_backend` setting.
sourceraw docstring

workspace-last-focusedclj

(workspace-last-focused db-info repo-id)

Workspace id from repo_focus for repo-id, or nil.

Workspace id from `repo_focus` for `repo-id`, or nil.
sourceraw docstring

workspace-list-activeclj

(workspace-list-active db-info repo-id)

Active workspaces for repo-id, newest first.

Active workspaces for `repo-id`, newest first.
sourceraw docstring

workspace-list-active-with-sessionsclj

(workspace-list-active-with-sessions db-info repo-id)

Like list-active but each entry is the {:workspace :session-state} pair, sorted by last_focused_at_ms DESC NULLS LAST, then created_at DESC.

Like `list-active` but each entry is the `{:workspace :session-state}`
pair, sorted by `last_focused_at_ms` DESC NULLS LAST, then
`created_at` DESC.
sourceraw docstring

workspace-list-finishedclj

(workspace-list-finished db-info repo-id)

Discarded workspaces for repo-id, newest first.

Discarded workspaces for `repo-id`, newest first.
sourceraw docstring

workspace-normalize-rootclj

(workspace-normalize-root root)

Canonicalize a workspace root string/File. Blank/nil → nil. Expand a leading ~ or ~/ against the current user's home directory.

Canonicalize a workspace root string/File. Blank/nil → nil. Expand a leading
`~` or `~/` against the current user's home directory.
sourceraw docstring

workspace-register-hook!clj

(workspace-register-hook! hook-id hook-fn)

Register hook-fn for hook-id ∈ {:on-spawn :on-apply :on-approve :on-discard}. Synchronous; exceptions swallowed.

Register `hook-fn` for `hook-id` ∈ {:on-spawn :on-apply :on-approve :on-discard}.
Synchronous; exceptions swallowed.
sourceraw docstring

workspace-rootclj

(workspace-root env-or-root)

Extract a canonical :workspace/root from an env map or raw root value.

Extract a canonical :workspace/root from an env map or raw root value.
sourceraw docstring

workspace-set-label!clj

(workspace-set-label! db-info {:keys [workspace-id label]})

Set the workspace's human-friendly :label. Empty/nil clears it.

Set the workspace's human-friendly `:label`. Empty/nil clears it.
sourceraw docstring

workspace-statusclj

(workspace-status db-info workspace-id)

Enrich a workspace record with live status. Stamps :workspace/root, :workspace/sandbox?, :workspace/exists?, :workspace/changed (count of since-fork edits) and :workspace/dirty?. No git.

Enrich a workspace record with live status. Stamps
`:workspace/root`, `:workspace/sandbox?`, `:workspace/exists?`, `:workspace/changed`
(count of since-fork edits) and `:workspace/dirty?`. No git.
sourceraw docstring

workspace-subdirsclj

(workspace-subdirs path)

Child directory names (non-hidden) of path, case-insensitively sorted. Empty vec when path is blank, not a directory, or unreadable.

Child directory names (non-hidden) of `path`, case-insensitively sorted.
Empty vec when `path` is blank, not a directory, or unreadable.
sourceraw docstring

workspace-trunk-infoclj

(workspace-trunk-info)
(workspace-trunk-info root)

The user's real cwd (trunk). No git read; just the launch dir.

The user's real cwd (trunk). No git read; just the launch dir.
sourceraw docstring

workspace-with-sessionclj

(workspace-with-session db-info workspace-id)

Hydrate workspace-id with its pinned session_state. Returns {:workspace <ws> :session-state <ss>}.

Hydrate `workspace-id` with its pinned `session_state`. Returns
`{:workspace <ws> :session-state <ss>}`.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close