All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
jail.mach_services becomes the platform-neutral jail.keychain: trueproject spellingproject spelling (a91d72e90)feat(live,extensions): LiveView.close(model_result=…) can return a model-specific string while preserving the complete final picture and focus snapshots exclusively for the human artifact. GitHub watches now return one compact JSON diagnostic with run metadata, every job’s id/outcome/timing and nested step list, plus one bounded log tail for each failed job; field schemas occur once and the artifact tree is never duplicated into that result.
fix(live,companion,extensions): finished live artifacts now retain a bounded picture for every row of a focusable table. Reopened GitHub runs can switch jobs locally to inspect each job's final steps and log after the watcher process has exited; these archive-only pictures stay out of the model verdict and live close broadcast.
refactor(extensions): the GitHub live view no longer renders a run-wide Activity feed that duplicated job states and selected-job steps. The job table remains the run overview, while selecting a row gives that job's steps and log; provider retries remain visible in the run status.
refactor(extensions): use the shared vis.testing.LiveRecorder harness for isolated open/patch/state/focus/close materialization and exact view comparisons. GitHub tests now retain only GitHub polling, fixtures and projections.
fix(live,companion,extensions): close GitHub watches replaced by newer commits with superseded, not finished. Queued and running jobs receive the same verdict; running-step indicators, focused-log updates and queued counters stop.
fix(companion,extensions): highlight every cell in the selected GitHub job row and refresh its steps and log from shared state before the next provider request. Distinguish run-wide activity from selected-job details.
fix(tui): place finished live runs beside the Python form that opened them. The transcript chevron opens or collapses the read-only record in the live panel.
fix(extensions): isolate Python extension tests from live user sessions. GitHub watch tests use an in-memory host; the test boundary rejects calls that would publish live views or attach NDJSON records to the conversation.
fix(extensions): show the GitHub run's start date and time in UTC alongside workflow, branch and focus.
fix(live,extensions): name live-view records *.live.ndjson with media type application/vnd.vis.live+ndjson, matching their append-only open/patch/close stream. GitHub watches retain the last valid view during transient polling failures and fail after three consecutive errors. Unknown unfinished states remain running, unavailable job logs are retried, and pull requests without checks finish neutral.
fix(companion): repeated saved cuts of one settled live run now render as one RUN row in the transcript, using the newest cut, instead of one identical row per version.
fix(extensions): an implicit GitHub watch now stops when a newer commit starts the same workflow on the same branch and event. The live card marks the old run as superseded, links to its replacement, and returns that reason to the model instead of polling obsolete work indefinitely; a caller that explicitly names a historical run still watches exactly that run.
fix(live,companion): publish live-view close events after attaching the record to its iteration, allowing Companion to refresh the transcript immediately. Records attached after block completion also reach the next model request as filename, attachment ID and read_attachment(…) reference.
fix(shell): support text slicing on shell log results: status_res.logs()[-4000:] slices out instead of raising KeyError. String-key lookup, JSON, mutation and iteration retain dictionary behavior; other shell result maps remain nonsliceable.
feat(shell): add shell-log pagination with next(page), next(page, None) and page.pages(max_pages=…). Pages preserve the original id, lines and limit; pages includes the current page and defaults to ten pages. Negative windows stop at byte zero; forward windows stop at the snapshot's EOF. Later output requires a fresh sh.logs(). Results remain dictionaries whose ordinary iteration yields keys.
feat(live): make GitHub watches interactive live views. Activity shows job and step changes plus newly failed job logs. Focusable job tables use shared is_focusable / focused_ids state across Python, engine, gateway and Companion. Running jobs are focused by default; user selections update steps and logs, persist across row updates and override stale polling defaults. Companion uses full-width 44px row controls with aria-pressed; non-focusable tables remain unchanged.
fix(live): show focused jobs' current step or runner wait while GitHub job logs remain unavailable. Job and step durations update on every poll, with an explicit log-publication note. When a job finishes, its raw log replaces the progress summary; transition history and failed-job log tails remain unchanged.
fix(engine): recover from Python contexts whose GIL remains locked after cancellation. After acquiring the turn lock, a bounded detached probe evaluates None; an unresponsive context is detached and replaced once per acquisition without blocking on disposal. Busy contexts are still awaited. Recovery may reset sandbox variables but preserves the conversation.
test(loop): make the sandbox-roots test list its own fixture directory instead of the whole home directory. This prevents native directory reads from exceeding the evaluation timeout and blocking context cleanup; the test file completes in 34 seconds.
fix(loop): preserve live-view records and already-printed output when a block is cancelled or times out. Engine-thread cleanup uses its own artifact collector, adds the record to the block outcome and includes its verdict in model-visible output.
refactor(language-surface): remove duplicate directory-grouped by-cwd results from format_code, lint_code and run_tests. Retain the flat findings, files and failures lists with full paths; update the contract and both language packs.
feat(python): add pagination to grep text results: next(g), next(g, None), bounded lazy pages() and all(). The page preserves the entire original options map and exposes next_offset; bounded aggregation reports remaining output. String operations, slicing, printing, .get('op') and character iteration remain unchanged.
refactor(shell): rename merged pty output to out / out_omitted_chars across run, handles, logs, wait, type and stop. Both stdout and stderr appear in order in this stream. Update shell cards, documentation and the standalone SDK; remove the stdout alias (issue #137).
fix(tui): render daemon-originated live views in the TUI by projecting gateway open/patch/close events. Preserve engine IDs and sequence numbers, log invalid frames, replay open views on mid-run attachment and ignore duplicate or outdated patches and closes.
feat(config): support explicit non-secret configuration values such as VIS_MANAGED: {literal: "true"} through the shared environment resolver. Managed REPLs, tests, shells and extensions use the same value. Bare scalar declarations and literals under credential-like names remain invalid. Per-call env deltas also accept the literal wrapper.
fix(python,cli): normalize common attachment, grep and shell keyword variants to canonical names while rejecting duplicate or unknown keys. Preserve normalized grep filters during content search and include the accepted vocabulary in errors. Aliases cover attachment filename/label/source, grep paths/include/context/limit and shell lines/seconds.
feat(shell): support forward and backward line windows in sh.logs: positive counts read after an offset, negative counts read before it. Backward windows never exceed their starting offset; truncated windows report is_eof false.
docs(python): generate attachment shim documentation from inspect.signature. Pages use __vis_calls__ / __vis_keys__, consistent required markers, per-key notes and Raw result descriptions; tests compare documented keys with live signatures in both directions.
fix(python): complete Pillow 10 helper-module APIs, including ExifTags, TiffTags.lookup, palette operations, ImageMath, parser context management, feature tables, ImageShow and GUI adapters. Apply UnsharpMask thresholds, preserve font arguments and variants, expose filter kernels and Color3DLUT.transform, and support image value equality, identity hashing, deepcopy, NumPy array access and format MIME types. Document remaining shim limitations in doc("pil").
fix(tui): give active TUI live views a stable four-fifths-height viewport. Use raw signed wheel deltas without transcript momentum. Focusable rows are full-width targets marked ○ / ●; selection uses the shared engine or gateway action and ordinary patches. Read-only completed records have no controls.
fix(tui): allow running TUI live views to collapse to a status row without stopping updates. The title control or status row restores the viewport; Escape restores it before showing the interruption-note field.
docs(cli): standardize tool documentation and validate language parameters against handlers. Document Python formatting/lint options, Clojure REPL connection options and language-specific test filters. Requiredness uses :required?; parameter notes have a six-word limit. Tests enforce note length, requiredness and key order across registered tools.
fix(tui,companion): show Vis is showing <view> — live (iter N) while a live view is open in TUI or Companion. Restore the ordinary turn phase after closure; completed runs appear in the transcript.
fix(extensions): update GitHub watches with changed jobs, focused steps and failed-job log tails as soon as each job completes. Poll every 3 seconds while jobs run and 8 seconds while queued. Return the final counters, failed job and log tail within the engine's 120-line budget rather than the full update history.
fix(python): support saving and reopening empty presentations by detecting ppt/presentation.xml rather than requiring slide files. Pin imaging 0.1.10, which fixes the incorrect workbook-format error.
fix(language-surface): accept project as cwd across language tools and reject conflicting directory values. Document actual requiredness and workspace-root defaults. repl_connect is Clojure-only and supports shadow-cljs builds; run_tests supports build selection; repl_start launches project REPLs and uses id as a Python/Bun label rather than a Clojure ID.
feat(clj-test): append requested deps.edn aliases to clean-JVM test runs, retaining :test and inherited JVM options. Accept aliases with or without a leading colon; reject them for lein/bb projects. Report when aliases cannot apply to reused nREPL or shadow-cljs runs. Document repl_start aliases as additions to :dev and :test.
fix(human-input): attach live-view records to their opening iteration when the block collector has already closed. Resolve the owning turn directly so an iteration's first artifact can be a live record. show completed runs as persistent transcript rows with title, verdict, line count and duration. TUI opens read-only records in the live panel; Companion opens them full-screen and fetches bytes on demand. Multiple completed runs remain accessible and expose no stop or input controls.
fix(python): normalize os.PathLike inputs in image-save and plotting shims before selecting file-object or filename behavior. PIL detects file objects by .write; plotting chooses the same format for string and Path filenames.
fix(extensions): remove the arbitrary 90-minute limit and minutes parameter from GitHub watches. Watches end on provider completion, an unrecoverable error or user interruption; the extension documentation defines the same lifecycle rule.
fix(human-input): suspend a block's evaluation deadline while it has an open live view. Restore the base budget from the time the view closes. Timeout or cancellation closes abandoned views with their current contents, while views deliberately retained between blocks remain open.
fix(companion): give live-status headlines full width and place detail text below them to avoid word-per-line wrapping on phones.
fix(languages): standardize REPL startup failures as message, exit and log_tail across languages. Drain child stderr from startup to avoid pipe blocking and lost diagnostics. Report running, pid and cmd only for live interpreters; failed Bun starts no longer register live resources.
fix(languages): standardize REPL lifecycle behavior: reuse live REPLs, reject changed environments by key, report environment names and digests, and use stopped/not-managed with status down. Centralize comparison and errors in process-jail; wait for the Bun handshake before reporting started.
refactor(language-surface): replace repl's op string with repl_start, repl_status, repl_stop and repl_connect. Keep bare-ID and language-led stop forms; remove restart in favor of explicit stop and start.
fix(language-surface): reject bare strings where REPL option maps are required. Honor IDs in status and stop calls, report resources alongside per-directory state and update messages that referenced removed repl APIs or session resource keys.
feat(shell): support per-call shell and REPL environment deltas over workspace dotenv and configured declarations. Null unsets a variable; source maps supply secrets without recording values in call arguments. Validate names and sources and reject unsafe process-initialization variables. REPL identity includes environment names and digests; changed environments require an explicit restart.
feat(python): return compact tree text from ls instead of structured rows. Include path and directory/file counts, two-character branches, expanded child counts, compact file sizes and blank-line-separated sections for multiple paths. Listings are rendered directly rather than indexed.
fix(python): flush a live view's first operation immediately after machine startup. Represent never-flushed state as None rather than 0.0 so monotonic-clock origin does not suppress the first update.
feat(extensions): add GitHub Actions live views with headline, job progress, counters, job table, focused steps, log tail and links. Poll every 5 seconds, slowing to 15 seconds after five minutes; read logs through redirected CLI output and state when GitHub has not published them. Shared pull-request mapping and Python/Clojure envelope tests verify engine acceptance. Replace the extension documentation sketch with this example.
save closed live views as application/vnd.vis.live+ndjson attachments addressed by vis-live://<session-id>/<view-id>, using read-only storage and inline bytes only below 256 KiB. Preserve interrupted views through the opening block's collector. TUI reopens completed views read-only; Companion displays RUN artifacts, reads only the ends of records above 1 MB and pages logs from the gateway.
refactor(gateway): replace the servlet-based gateway adapter with Jetty 12 core via info.sunng/ring-jetty9-adapter. Streaming Ring responses use a direct Handler; dependencies decrease from 22 to 10 jars by 1.66 MB. Remove obsolete Jetty CVE pins and ee9 HttpOutput initialization settings. Disable Jetty's separate shutdown hook so stop! remains responsible for cancelling and draining turns before socket closure.
feat(gateway): support remote gateway targets through --gateway / --gateway-token or VIS_GATEWAY_URL / VIS_GATEWAY_TOKEN. Remote calls do not discover, spawn or manage a local daemon and do not claim a local PID. Support tokenless SSH-tunnel targets; invalid or unreachable targets fail without local fallback. Each TUI process uses one gateway; status and pair use that target, stop refuses remote targets, and --db does not apply.
fix(gateway): read string-keyed gateway status correctly instead of reporting a running daemon as stopped.
feat(clj-repl): attach Clojure REPLs to shadow-cljs builds alongside managed JVM REPLs for the same directory. Validate build existence, watch state, nREPL type and connected JavaScript runtime; preserve the selected build for later evaluations.
feat(clj-test): run selected ClojureScript tests through the project's shadow-cljs build, using :ns-regexp and optional build selection. Determine results from printed counts because shadow-cljs can exit zero after test failures.
fix(clj-test): answer a run_tests path that is NOT on disk with no such path plus the deepest part of it that exists, instead of "no tests under it"
fix(clj-test): select *_test.cljc files — a .cljc test namespace was invisible to run_tests
feat(clj-test): run_tests runs the clojure namespace a call names — ns / nses / namespace / namespaces and var / vars / only select instead of being refused
fix(extensions): make vis.state a whole mapping — pop, setdefault, update, clear, keys and iteration
refactor(editing): remove structural editing — struct_index, struct_nodes and struct_patch are gone; grep → cat → patch is the whole editing surface
feat(python): cover asyncio queues, locks, futures and timeouts in the sandbox shim
fix(python): resolve tools passed to asyncio.to_thread or run_in_executor within their gather slots
build(ci): pause scheduled beta native builds after failures on all native platforms; retain manual dispatch
fix(build): identify dev builds as a separate track and reject dev as an update target
feat(companion): open search across machines by pulling down the session list
fix(companion): move the pull-to-search indicator with the touch gesture
feat(companion): keep an unsaved comment and let it be edited
build(ci): build the macOS asset on our own runner, and watch the queue
build(ci): release JVM-only builds until native platform checks pass
feat(voice): download pocket-tts with every other model
fix(copilot): authenticate only the account tier associated with the credential
fix(tui): remove a provider for good, credential included
refactor(tui): drop provider Log Out for Remove, and ask inside the transient
refactor(tui): show provider and MCP questions in the panel that initiated them
fix(providers): Preserve the default-root marker across machine updates
THIRD_PARTY_MODELS.md, generated from the manifesttype(scope): summary with a body of at most six WHY lines and a mandatory Vis-Session: <uuid> trailerfold_session(key, gist) takes a key and a gist and nothing else: the key is a string — "t2/i5" one step, "t2" a whole turn, "t2/i1-i9" a range, "-t2/i9" everything through it, "t2/i5-" everything since it, commas union severaljail.environment selects declared or inherit for child environments. The default includes project dotenv values, environment declarations and a non-secret basic allowlist. Inherit includes ambient values, including secrets, without changing other confinement. Variables that could interfere with jail initialization remain rejected.Replace the notification token list with a device-to-machine connection row and switch. Show Checking, Connected or Not connected consistently for APNs, FCM and Web Push. OS-disabled permissions are not reported as connected; iOS offers a system Settings link.
Copy session IDs as vis_session_id#<uuid> from TUI and Companion. read_session and get_session accept this marked form directly; introspection instructions describe it.
Use one Companion microphone control: tap to activate the current mode and hold for 450 ms to switch between dictation and voice conversation. Right-click and Shift+Enter also switch modes. Remove separate mode and exit controls. Exiting releases audio, recordings, speech, queued utterances and leases. Entering conversation mode enables it; the next tap starts recording. Icons and accessible names identify the mode and gesture.
Set the JVM maximum heap to -Xmx5g instead of 75% of host RAM. This gives concurrent GC and memory-pressure thresholds a consistent limit across machines rather than allowing a roughly 27 GiB maximum on a 48 GB host.
Allow comma-separated or repeated Android --track values, defaulting to internal,alpha,beta. Assign the build to all selected tracks in one transactional Play edit. Production remains explicit; reject multi-track staged rollouts before building.
Distribute iOS releases to internal TestFlight groups and the public group after Beta App Review by default. --audience internal restricts distribution to the team. Validate the audience before archiving. Product release tags target tester channels in both stores rather than Android beta alone.
Discover tester channels from the stores with --track all and --audience all. Play updates all discovered non-production tracks in one edit and validates names before building. TestFlight assigns external groups and internal groups that need explicit assignment. Both GitHub workflows use all.
Use paths to select tests in every language. Clojure maps test files, source files and directories to test namespaces. Remove ns, namespace and namespaces selectors and explicitly reject the old options rather than running the full suite.
Select individual tests with <path>::<test-name>. Keep each name paired with its file; Clojure maps source names to test namespaces and accepts pathless var names. Remove Clojure only and Bun filter options. Python forwards node IDs to pytest and uses -k for pathless names; the whole-file GraalPy runner rejects individual-test selection and recommends the project environment.
Make language packs return pass, fail, errored, command and is_pass directly. Remove shared result-name translation so each pack applies its runner's count semantics. Python call options use environment; configuration uses python.runner. Remove runner/interpreter call aliases.
Rename session_state to read_session, sessions to list_sessions and session_fold to fold_session, without aliases. Add get_session for one descriptor without a transcript. Replace list_sessions' channel filter with search, using the same title/request/reply/thinking ranking as TUI and Companion. Results include rank, match flags and request/reply snippets.
Android voice capture now opens a connected Bluetooth headset's HFP/SCO microphone before WebView starts recording, then restores the normal audio route when recording ends.
Voice-conversation playback on Android now uses the system text-to-speech engine when WebView does not expose the Web Speech API.
Voice conversation requests the spoken projection for an idle session as well as a queued one; previously the usual idle path returned only the full on-screen answer.
Prepare vis-foundation-bridge for Bridge 0.3: migrate the project profile and policy to the
reduced YAML schema, recognize every 0.3 profile filename, preserve exact validation paths, and
keep malformed Bridge configuration from crashing ordinary filesystem access.
Allow branch-dispatched Native Release dry runs to build the image, stage the bundle and run smoke/native tests without publishing. Only v* refs publish artifacts.
Move macOS arm64 native releases to GitHub-hosted macos-26 and remove the self-hosted runner. Use a 14 GiB maximum / 2 GiB initial heap with ParallelGC and swap for the 3-core, 7 GiB runner; log resource measurements. Keep VIS_MACOS_ARM64_RUNNER as an optional hosted-runner override. Cache dependencies and smoke-test the gateway; manual release builds remain available on Macs with at least 32 GB RAM.
Remove shell stderr and stderr_omitted_chars fields and the STDERR card section (issue #137). Pty commands and the internal blocking runner merge stdout and stderr into one output stream.
The agent prompt and the shell docstrings spell the keystroke method sh.type("y"), never a
bare sh.type() (issue #137): it SENDS text and its argument is required, so the old spelling
among the status accessors raised a TypeError for anyone who followed it.
The process-jail doc page is jail.md ("Process jail & egress"), not sandbox.md: in this
repo sandbox now names only the in-process GraalPy sandbox, and jail names OS confinement —
the same split the config keys and session["access"] already use. Every in-tree link moved
with it.
Require one options map for grep and struct_nodes, also accepting equivalent keyword arguments. Remove positional forms and report the canonical call shape when rejected.
Expand / into a skill reference, task, project and resource paths rather than the full skill text. The model reads doc(name) if the instructions are not already present. Repeated skill expansion is stateless.
Load workspace .env and .env.local by default for shells, managed REPLs, tests and Python extensions. Resolve environment declarations before dotenv and startup environment values. Use declarations for renames, keychain items, helper commands and explicit ambient access.
Include project dotenv values in confined child environments while keeping ambient operator variables denied by default. Reject unsafe process-initialization variables from dotenv and declarations alike.
Use jail for confinement terminology. Session access reports is_jailed; workspace copies report isolated instead of sandbox. Reserve sandbox for the Python execution environment.
CI: {env: CI}. Confined children still omit undeclared ambient variables and reject unsafe process-initialization names.extensions.env-passthrough, a third list of the same names: extensions was never a valid
top-level config key, so the block was rejected before anything could read it.git tool. There is no model-facing Git schema, no git binding in the sandbox and no
foundation-git extension: a Git command is an ordinary shell command, run by the same
jail, capture and timeout as everything else. Workspace Git FACTS (footer status, environment
block, file picker) and the TUI Magit surface are unchanged.Accept complete cat, grep and struct_index anchor rows by stripping the display separator and text before parsing the hash. Previously, including the line text caused valid printed anchors to fail. Replacement text containing a separator remains literal.
Honor supported requests, httpx and urllib3 TLS options instead of silently discarding them (issue #141). Preserve ssl, select and selectors imports; only asyncio still uses import rewriting. Emit the standard warning for unverified requests.
Handle string, bytes and PathLike certificate paths consistently, respect configured CA-bundle environment variables unless trust_env is disabled, and preserve SSL/configuration error types. Apply TLS version bounds, expose create_urllib3_context and explicitly reject unsupported options rather than ignoring them.
Ignore default/fallback provider and model selections in committed project vis.yml/vis.yaml, with a warning directing users to personal configuration. Retain those settings in global config, machine state and gitignored project overlays (issue #140).
Initialize Lanterna TTYDeviceControl at native runtime rather than build time. This avoids unusable foreign-function handles and startup crashes in v0.1.33–v0.1.35; use registered termios support or Lanterna's stty fallback.
Add :image-nses to extension manifests for namespaces resolved by name. Compile them into native images without eagerly loading them during discovery. Add reachability tests to detect omitted TUI, SQLite and voice namespaces.
Share Android JDK discovery between release preflight and build through scripts/jdk.mjs. Require stock JDK 21, including SDKMAN installations, and reject GraalVM because its jlink is incompatible with AGP JdkImageTransform.
Test the pty bridge with a real pseudo-terminal running cat. Cover replay, live output and typed-input echo rather than only a listener/send stub.
Include missing built-in extension namespaces in native build initialization and test the list against runtime discovery. This fixes startup failures caused by missing introspection and shim classes.
Restore Linux native releases by omitting Lanterna FFM TTY downcall registration, avoiding the TUI smoke-test SIGSEGV seen in v0.1.33–v0.1.35. Linux uses Lanterna's stty fallback, as through v0.1.32; macOS retains native calls.
Report the push relay before Web Push in capabilities so automatic VAPID configuration does not hide the native provider. Route browser devices through Web Push rather than reporting an unsupported platform.
Store a Var rather than a function value in the provider router-rebuild hook so namespace reloads use the current implementation.
Keep pasta diagnostics out of jailed command output by using --quiet and a process-specific log file under ~/.vis/logs.
Preserve JVM interruption across best-effort catch blocks in process, Git, gateway, credential, jail and MCP operations. cancellation/preserve-interrupt! restores the flag after InterruptedException but not CancellationException. The MCP listener exits on interruption.
The prompt's Clojure run_tests note said the opposite of what the runner does. It claimed the
managed REPL does "NOT reload namespaces automatically" and told a session to reload every
changed test namespace, while the runner already (require … :reload)s (or load-files)
every namespace it RUNS — and never their dependencies. Proven at runtime: a poisoned Var in a
test namespace came back restored from a run, the poisoned Var in the production namespace that
test requires did not. The prompt line, run-form's docstring and the repo guidance now name
the real trap: a changed PRODUCTION namespace keeps the Vars the reused REPL already holds.
Restore the interrupt flag when shell usage sampling is interrupted, returning no measurement. Cancelled sh.wait calls now stop rather than continuing to their deadline.
Remove the obsolete tool_name lookup, SessionArtifact.tool field and related screen-reader caption branch from the artifact gallery. Retain turn and iteration provenance.
Make capfd capture actual file descriptors in the sandbox pytest shim (issue #138), including os.write, C-level and child-process output. Drain redirected pipes during the test, include captured bytes in CaptureResult and replay unread output on failure. capsys remains stream-only.
Correct documented language and structural-tool calls to match runtime contracts: explicit language options, paths versus path, edit batches, Python True and one-options-map calls. Add a corpus test for every doc/apropos document.
Include failed Python test identities and messages in structured results. The project runner reads pytest JUnit XML; the GraalPy runner converts per-test records. Truncate output in the middle to retain the session header, failure details and summary, reporting the omitted character count (issue #136).
Accept PIL images directly in attach, alongside paths, bytes and matplotlib figures. Use JPEG for .jpg filenames with compatible mode conversion and lossless PNG otherwise. Reject unsupported source types explicitly rather than interpreting their repr as a missing path.
shellwait the only difference between a run and a background shellshell (25089f16f)wait the only difference between a run and a background shell (634c0476c)shell (25089f16f)wait the only difference between a run and a background shell (634c0476c)ls native tool with a sandbox ls() helperls native tool with a sandbox ls() helper (d3db4c514)match a sub-expression selector under every locatormatch a sub-expression selector under every locator (6d78ec191)human-input: let extensions ask typed questions with vis.ask or vis/request-human-input!. TUI, gateway and Companion present the same fields, validation, submit and cancel actions. Supported fields include plaintext, password, multiline, select, multiselect and checkbox. Require snake_case keys and enforce is_required across clients and HTTP. Cancellation and timeout return a falsey Answer with a reason. Passwords return opaque vis-secret handles; reveal resolves them in-process and forget removes them. Documented in resources/vis-docs/extending.md.
config: add conditional filesystem roots using when.os, when.exists and optional. Omit roots unavailable on the current host before building the jail, including their allow-list references. Doctor reports conditional skips as info and missing required paths as warnings.
config: allow explicitly declared macOS Mach services for confined children. The keychain option grants required security services and keychain-directory access while excluding those directories from default search. Additional services require explicit names; access remains denied by default and errors identify missing permissions.
change(drafts): persist rift 0.0.10-10's actual copy mechanism as workspace_mechanism: btrfs, reflink, apfs, worktree or copy. Store NULL when the backend does not report it; existing drafts remain usable.
change(drafts): use rift 0.0.10-9's recorded pruned paths rather than duplicating backend filter rules. Preserve tracked artifact directories and matching Git status. Older clones without a marker use the source repository's ignore rules.
fix(native-image): register BigInteger(String) and BigInteger(String,int) constructors in reachability metadata. This fixes YAML integer parsing and tools.reader failures in native commands outside the repository root; tests enforce both registrations.
fix(drafts): exclude paths omitted during cloning from the deletion diff used by /draft apply. Ignored and generated directories absent from gitignore-aware forks no longer cause deletion of source-repository files.
fix(drafts): exclude untracked, ignored files generated within a draft from changed-paths and /draft apply. Force-added tracked files remain included.
fix(drafts): prevent /draft apply from deleting committed Yarn artifact paths omitted by the fork, including .yarn/cache, unplugged, install-state.gz and build-state.yml. Continue reporting actual deletions in patches and releases.
draft policy (shared, copy-only,
copy-and-apply, not-allowed) in resources/vis-docs/configuration.md,
resources/vis-docs/sandbox.md, and resources/vis-docs/drafts.md, replacing
the stale claim that filesystem roots are not draft-specific.bs4 shim: match BeautifulSoup 4.12's TypeError for None input. Verify soupsieve and tree-builder behavior against beautifulsoup4 4.12.3 and soupsieve 2.5.
release: the workflow's "Commit release notes" step rebases onto
origin/main and retries, so a main that moved during the run no longer
fails the release job and skips the mobile release with it.
persistence: detect database replacement by filesystem device/inode identity rather than size and modification time. Normal WAL checkpoints no longer trigger repeated SQLite pool closure, leaked housekeeping threads or SIGBUS during live queries.
cancelled when the cancel itself throws, and bind cancels to turn numbersvis-agent is one coherent surface — run Vis, vis-agent runtime show|use native|jvm|dev|auto, and vis-agent update [--native|--jvm|--dev] [--rebuild] [vX.Y.Z|<ref>]. Vis follows releases by default and dev is the
only runtime that follows a moving branch.bin/install-vis-agent --runtime native|jvm installs the wrapper
and lets it acquire its own runtime, so wrapper and runtime cannot drift.--source alias, the --jar tombstone, the wrapper-owned
native/uber build commands, VIS_SOURCE_DIR, and VIS_LOCAL_BIN_DIR.bin/install-source (use install-vis-agent --runtime jvm).~/.vis/source-dir, ~/.vis/sourcecode, ~/.vis/install/mode, and
~/.vis/install/sha. Runtime state is now ~/.vis/runtime plus
~/.vis/install/{vis-agent-native,src,ref}.vis-agent update --native|--jvm|--dev reaches the update path
again; the launch-flag parser previously discarded those flags. A final
[[ … ]] && cmd no longer makes a successful runtime use exit 1.dev runtime names one checkout. When $VIS_DEV_CHECKOUT does
not hold one, vis-agent now says so instead of silently running whichever
checkout the launcher happens to sit in.runtime and update are listed by vis-agent --help and are owned by
the launcher, so the binary no longer advertised a second, different update
that failed on its own documented flag.vis-agent --modle gpt-5 "task" used to run with the DEFAULT model
and a polluted prompt; it now exits 2 naming the flag. A value flag left
without a value is refused the same way, --verbose/-v are consumed as
debug flags, and -- ends flag parsing for prompts that start with dashes.runtime use and JVM/dev launches report a missing runtime,
missing clojure, or missing java with the command that fixes it, instead
of exiting 127 from exec.VIS_HOME that is a
file, a ~/.vis/runtime that is a directory, or an unwritable home reports
the path it could not write instead of claiming "runtime is now …".--, or flag-shaped value. --model ""
used to run the default model and --model --json task used to request a
model literally named --json.--json --code, --stream-json --code, …) are
refused instead of silently honouring one and dropping the other, and an
unusable --db path is named instead of surfacing a raw SQLite pool error.--help described --persist as the opposite of what it does, twice.cwd across the tool surfaceis_stateless for gateways that reject replayed item idscwd across the tool surface (4df25f19e)is_stateless for gateways that reject replayed item ids (41f87ea34)cwd across the tool surface (4df25f19e)cwd across the tool surface (4df25f19e)cwd across the tool surface (4df25f19e)br/check and br/run-evidence.vis-foundation-bridge now targets the Bridge 0.2.2
candidate-verification API.struct_patch moves no longer drop the file's trailing newline (or \r):
the structural editor now splits lines without collapsing the final empty
line, and only collapses a seam when there is one.python.source_pathsvis python -m ruff, formatted shimsvis update explain and recover from diverged history (#53)python.source_paths (f8ac1d4ec)vis python -m ruff, formatted shims (83082fdb9)vis update explain and recover from diverged history (#53) (f369fdaed)vis python -m ruff, formatted shims (83082fdb9)compatibility key, svar model limits, vis.yml model ordercompatibility key, svar model limits, vis.yml model order (1c2478678)/draft-blank under the draft tree as /draft blank <label>/draft-fresh slash command to /draft-blank (empty drafts start with no HEAD files)vis python standalone interpreter exposing GraalPy sandbox + shimsvis gateway start and refresh statusvis python standalone interpreter exposing GraalPy sandbox + shims (1afcec09)vis gateway start and refresh status (2144797e):ext/nudge-fn for per-iteration system nudges from extensions:ext/requires for extension dependency declaration:ext/version, :ext/author, :ext/license metadataregister-global!, load-extension!, reload-extension!extensions/common/vis-foundation package (read, list, grep, patch):balanced (was :quick)create-env -> create-environmentdispose-env! -> dispose-environment!vis! -> query!register-env-def! removed (use extensions)loop/nudges.clj to loop/runtime/prompt.cljsession/shared.clj folded into session/core.cljvar-diff (dead code)restore-var references (never existed as callable tool)resources/docs/)github-copilot-provider-id? omitted :github-copilot-enterprise, so
enterprise models were filtered out of the visible catalog mapping.Can you improve this documentation? These fine people already did:
Karol Wojcik, blockether-deployer, Wojciech Franke, michal-blockether & vis-agentEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |