Vis

Runtime distributions

For everyday use on a supported Linux or macOS host, install the prebuilt native release. It does not need Java. The dev track runs from source on the JVM. Both install vis-agent, which runs the engine and gateway, and vis-tui, the terminal client that connects to it. The desktop apps connect to the same gateway from Windows, macOS or Linux.

When to use

To add Java or Clojure code inside the engine, see Native builds for Java and Clojure extensions.

Native vs JVM

Choose native for everyday use. Choose JVM when developing Vis itself or running the latest code from main.

What matters Native JVM
Best for Daily work and multiple sessions Developing Vis and trying the latest changes
Version track release (default) or beta dev
Java / Git Not needed Git and JDK 25+
Gateway startup ~0.7 s ~8.6 s
Gateway RAM ~122 MiB ~566 MiB
RAM per session (light use) ~60 MiB ~153 MiB

Approximate figures, measured on an Apple M4 Max.

Installing

curl -fsSL https://github.com/Blockether/vis/releases/download/installer/install-vis-agent | bash

By default the installer downloads the latest complete stable native release. It puts the engine, bundled Python worker and matching TUI in ~/.local/bin and adds that directory to the shell profile if needed. Use --install-dir PATH to change it. Native installation requires curl and tar, not Java or Git. Missing or incomplete native packages fail without installing a JVM fallback.

The installer accepts the same tracks as update:

curl -fsSL https://github.com/Blockether/vis/releases/download/installer/install-vis-agent | bash -s -- --track beta
curl -fsSL https://github.com/Blockether/vis/releases/download/installer/install-vis-agent | bash -s -- --track dev

The bootstrap scripts refresh after successful main CI, independently of stable releases. They are published as GitHub release assets because some networks block raw.githubusercontent.com. Native installations still use the matching launcher from their selected release. Running bin/install-vis-agent from a clone also works.

Pin an exact version

Use --version when a CI pipeline or a team must stay on a tested release or beta. The installer then installs exactly that build, never a newer one.

curl -fsSL https://github.com/Blockether/vis/releases/download/installer/install-vis-agent | bash -s -- --version 0.2.46
# The same with an environment variable:
curl -fsSL https://github.com/Blockether/vis/releases/download/installer/install-vis-agent | VIS_AGENT_VERSION=0.2.46 bash

You can write 0.2.46 or v0.2.46. The installer takes the vis-agent command from that release and runs vis-agent update v0.2.46. If the release does not exist or has no bundle for your platform, the installation stops. It never falls back to the latest release. A stable version selects the release track, so you cannot add --track beta or --track dev.

To pin a tested beta, give its full tag: beta- and the 40-character commit. vis-agent switch list shows the published beta tags.

curl -fsSL https://github.com/Blockether/vis/releases/download/installer/install-vis-agent | bash -s -- --version beta-<commit>

A beta tag selects the beta track, so you cannot add --track release or --track dev. The installer runs vis-agent update beta-<commit>. The update takes the engine, Python, TUI and web app from that beta. It checks each download against the SHA256SUMS of the beta. The installation stops if the beta does not exist, has no SHA256SUMS or misses a selected part. It never falls back to the latest beta, and the installed build and track stay the same.

Choose what to install

By default the installer adds the terminal client (TUI) and the web app. If you use only the vis-agent command line, for example on a server or in CI, install less with --components:

# Only the command line, the engine and Python:
curl -fsSL https://github.com/Blockether/vis/releases/download/installer/install-vis-agent | bash -s -- --components none
# The TUI, without the web app:
curl -fsSL https://github.com/Blockether/vis/releases/download/installer/install-vis-agent | bash -s -- --components tui
# Everything, and the desktop app now:
curl -fsSL https://github.com/Blockether/vis/releases/download/installer/install-vis-agent | VIS_COMPONENTS=all bash
Component What it adds
tui The terminal client for vis-agent tui.
web The web app for vis-agent web.
desktop The desktop app, downloaded during the installation.

The engine and the Python runtime are always installed. Use none, all or a list separated by commas. Vis saves your selection, and vis-agent update keeps it. To change it later, run vis-agent update --components tui,web. An update removes the parts that you do not select. Without desktop, vis-agent desktop still downloads the desktop app the first time that you open it.

Verify what you download

Each release publishes SHA256SUMS, with the SHA-256 hash of each of its assets. The installer checks the vis-agent command against this list before it runs it. vis-agent update checks each archive before it unpacks it. A changed file or a missing entry stops the installation, and the installed version stays. Older releases have no SHA256SUMS, so Vis installs them with a warning.

SHA256SUMS comes from the same place as the assets. In CI, keep the hashes in your repository instead, so a replaced asset cannot pass. Pin the installer with sha256sum --check, and pin the vis-agent command with --sha256 or VIS_AGENT_SHA256:

tag=v0.2.46
base=https://github.com/Blockether/vis/releases/download/$tag
curl -fsSLO "$base/install-vis-agent"
echo "<installer hash>  install-vis-agent" | sha256sum --check
bash install-vis-agent --version "$tag" --sha256 "<vis-agent hash>"

With a stable --version, the command comes from that release, so its hash does not change. A beta publishes no separate command. With a beta tag, the installer uses the command of the rolling installer assets, so its hash changes when they refresh. The update then installs the command from the beta bundle. A different command stops the installation before it runs.

To check release assets by hand, download them and SHA256SUMS to one directory:

tag=v0.2.46
base=https://github.com/Blockether/vis/releases/download/$tag
curl -fsSLO "$base/SHA256SUMS"
curl -fsSLO "$base/vis-agent"
sha256sum --check --ignore-missing SHA256SUMS

The expected output is vis-agent: OK. On macOS, use shasum -a 256 --check --ignore-missing SHA256SUMS. Use sha256sum vis-agent to get the hash to pin.

Updating and selecting a track

vis-agent update                          # release, always the default
vis-agent update --track release          # latest complete stable native release
vis-agent update --track beta             # latest complete native beta
vis-agent update beta-<commit>            # that published beta build
vis-agent update --track dev              # newest main source, always JVM
Track Source Execution
release Latest complete stable GitHub release Native engine, gateway, workers and TUI
beta Published beta of a main commit that passed CI and native checks Native engine, gateway, workers and TUI
dev Newest commit of main JVM engine, gateway, workers and TUI

Every update without --track or a beta tag selects release, also after beta or dev. A successful update records the selection for later launches. To stay on beta or dev, name that track in each update. A failed download does not change the recorded selection. Dev ignores any native binaries from a previous install.

vis-agent update vX.Y.Z installs a specific stable version on the release track. vis-agent update beta-<commit> installs that published beta on the beta track. A missing, incomplete or unverified beta stops the update. Dev accepts no version pin. Native updates acquire the engine, Python worker and TUI from the same immutable release before replacing installed files. A missing native TUI fails rather than starting a JVM client.

How you learn that a newer version is running

The gateway is a daemon that keeps running after the command that started it ends. So the gateway can already run a newer Vis than your client. For example, an open TUI can stay alive through an update, or you can point a client at a gateway on another machine.

When the client and the gateway run different releases, Vis tells you in three places:

  • The terminal client prints one line per run.
  • The TUI shows a notice in its header.
  • vis-agent gateway status names both releases.

Vis refuses nothing, because both halves still use the same wire protocol. To close the gap, run vis-agent update on the machine that is behind.

Switching between versions

update follows a track forward. switch names the build that you want to run. So you can move to a published beta to try a fix, and then back to the stable release.

vis-agent switch list                     # installed build, tracks and published versions
vis-agent switch release                  # newest stable release
vis-agent switch beta                     # the beta the installer index selects today
vis-agent switch v0.2.46                  # that stable release
vis-agent switch beta-<commit>            # that published beta build
vis-agent switch dev                      # newest main source, always JVM

switch list first prints the installed version and track. Then it lists the tracks, the published releases and the published betas, and marks the entry that the installed build came from. It needs GitHub only for the published lists. If Vis cannot read them, you can still name a version.

A switch installs the bundle it names through the same installer update uses, and records the selection, so later launches use it. Configuration, sessions and extensions are shared by every version, so switching back costs only the download. --keep-gateway leaves a running gateway alone, exactly as it does for update.

If managed source already exists in ~/.vis/install/src, a native update also pins it to the exact commit of the selected native build. This needs Git. Native-only installations do not download source.

If that checkout has staged, unstaged or untracked changes, the update stops and shows the checkout path. Commit or stash your changes, then run the same command again. Until then, nothing changes: not the source, the native installation or the selected track. A failed source fetch also changes nothing.

Managed source is a detached commit, not a tracking branch. For a manual pull, name a branch.

An update stops an idle managed gateway before it replaces the files. It never stops a busy gateway or one that you started yourself. Add --keep-gateway to leave an idle gateway running too.

Dev needs Git and JDK 25+. The launcher can install the Clojure CLI. VIS_NO_AUTO_INSTALL=1 disables that installation. Dev does not build native images. To run local repository edits independently of installed tracks, use clojure -M:vis inside that checkout. Build those edits with clojure -T:build native.

One-launch JVM override

Use --jvm to run on the JVM without changing the installed track:

vis-agent tui --jvm
# Equivalent:
vis-agent --jvm tui

# Start a foreground gateway on the JVM:
vis-agent gateway start --jvm
# Equivalent:
vis-agent --jvm gateway start

The flag applies to this launch only and is consumed by the launcher, not the engine or terminal client. It uses the managed source in ~/.vis/install/src. If no managed source exists, a checkout-owned launcher uses its own source tree: ./bin/vis-agent tui --jvm. An installed launcher with no source reports how to install it with vis-agent update --track dev. It does not download source or change tracks automatically. JVM execution requires JDK 25+.

For gateway inspection and control commands, --jvm selects the local command's runtime. It does not change the runtime of an already-running or remote daemon.

--jvm is not an update option. Use --track dev to install or update JVM source. Arguments after -- or python uv are passed through unchanged.

Terminal gateway lifecycle

vis-agent tui discovers the local gateway and starts one when none is running. A native installation starts a native gateway. Dev or an explicit --jvm launch starts it with the same JVM and engine classpath. A compatible gateway already serving other clients is reused, never killed to change its runtime.

You do not need to start a gateway before you run vis-agent tui. A start can take a while, most of all with --jvm, which runs Vis from source. vis-agent tui waits while the new gateway starts. If the start takes longer than 15 seconds, it prints the path of the gateway's boot log under ~/.vis/logs/. If the gateway exits before it is ready, or is not ready after 10 minutes, vis-agent tui stops. It then shows the last lines of that boot log, so you can see what went wrong.

The launcher holds a client lease until the TUI exits. The TUI also registers its local PID so crashed clients and their event streams can be reaped. A managed gateway stops after its last client disconnects and no work remains. Closing one TUI does not stop another TUI, the companion, or an active turn. Manually started gateways remain user-owned.

--gateway or VIS_GATEWAY_URL selects an explicit gateway: the TUI only connects to it and never starts or stops a local replacement. If your shell profile sets VIS_GATEWAY_URL, unset it to let vis-agent tui start a local gateway again. Help and version commands do not start a gateway. Direct vis-tui execution remains a connection-only client. Use vis-agent tui for automatic local lifecycle management.

Open the web app

The web app is the Companion app, served by your own gateway. Use it to open Vis in a browser without a desktop app. It works on the computer where Vis runs and on other devices on your network.

vis-agent web                  # use or start the gateway on 127.0.0.1:7890 and open the app
vis-agent web --port 8080      # use or start the gateway on port 8080 instead
vis-agent web --host 0.0.0.0   # also serve other devices on your network
vis-agent web --no-open        # print the address without opening a browser
vis-agent web --pair           # also print a pairing QR for the Companion app on your phone

The command prints the address it opens. Keep it running while you use the app, and press Ctrl-C when you are done. If the gateway stops answering, the command ends and tells you. vis-agent gateway start serves the web app too, and prints its address when the web app is installed.

The address that vis-agent web prints connects the browser to this gateway. You do not type a token. The address works once, within 5 minutes, and does not contain the gateway token. If the address is too old or was already used, the web app shows an error and the connection screen. Run vis-agent web again to get a new address.

With --no-open, open the printed address yourself, or give it to a script that opens it. A script can replace the host with localhost and keep the rest of the address.

--pair prints the same pairing block as vis-agent gateway start --pair: the link, the token and a QR code. Without --host, it starts the gateway on an address that your phone can reach. --advertise sets the address in the pairing link, as it does for vis-agent gateway start.

Voice input works only on a secure page: HTTPS, or localhost and 127.0.0.1 on the computer that runs Vis. Browsers block the microphone on other http:// addresses. For example, a Windows browser that opens the address of Vis in WSL cannot record. To allow such an address in Chrome:

  1. Open chrome://flags/#unsafely-treat-insecure-origin-as-secure.
  2. Add the address of the web app, for example http://172.20.1.2:7890.
  3. Set the flag to Enabled and relaunch Chrome.

Choose the gateway address

--host and --port name the gateway the web app uses. They default to 127.0.0.1 and 7890.

  • If your gateway already answers at that address, the web app uses it.
  • If no gateway is running, vis-agent web starts one there.
  • If your gateway runs at another address and nothing uses it, vis-agent web restarts it at the new address. Some gateways stay where they are: a gateway that another Vis session uses, or one that you started with vis-agent gateway start. For those, the command tells you where the gateway runs and how to open the web app there.
  • If the host is another machine, or another gateway already answers at that address, vis-agent web opens the web app of that gateway. Set VIS_GATEWAY_TOKEN when that gateway requires a token.

A gateway bound to 0.0.0.0 or to a network address always requires its token, also in your own browser. The address that vis-agent web prints gives the token to that browser. On other devices, the web app asks for the token, and vis-agent gateway pair shows it. The command also prints the addresses that other devices can open.

Get the web app

Release and beta builds publish the web app with the native runtime. vis-agent update installs it next to the runtime, so you do not need Node.js. If the web app is missing, the first vis-agent web downloads the copy published with your installed build.

The dev track runs Vis from source. There, the first vis-agent web builds the web app with Node.js and npm. Later runs rebuild it only after the Companion sources change. A gateway that is already running serves the new build without a restart. To serve a different build, set VIS_WEB_DIR before the gateway starts. Point it to a directory that contains the build's index.html.

Open the desktop app

  1. Download the installer from GitHub Releases for your computer.
  2. Install the package and open Vis from your application launcher.
  3. Connect to your gateway to open your projects and continue your sessions.
Platform Package Install
Windows 10/11 x64 .msi Run the installer.
macOS, Apple silicon or Intel Universal .dmg Open the disk image and copy Vis to Applications.
Linux x64 or ARM64 .AppImage or .deb Make the AppImage executable and open it, or install the Debian package with your package manager.

The Windows installer downloads Microsoft Edge WebView2 if needed. Installation may require network access and administrator approval. To update the app, close Vis and install the newer package from the same release page.

Each published beta has the same installers. A desktop fix can reach a beta before a stable release. To try it, download the installers from that beta's prerelease on the releases page. A beta package installs as the same Vis app as the stable package. To keep your stable app, use vis-agent desktop --track beta on macOS or Linux instead.

Run the gateway on the computer where your projects live: macOS, Linux, or Linux in WSL2 on Windows. For a local WSL2 gateway, enable localhost forwarding. The connection guide covers both local addresses and remote pairing. Isolated drafts have more filesystem requirements.

Notifications on the desktop

The desktop app raises a system alert when a session on a connected machine answers you or asks you a question. The alert carries the session's name and what Vis said, the same as the alert on your phone. Turn it on for each machine in Settings, under Notifications: pick the machine and switch its notifications on. macOS asks for permission the first time, and System Settings, under Notifications, controls how those alerts appear.

Alerts arrive while the desktop app is open. It cannot receive push notifications, so nothing reaches it after you quit. To hear about a session while the desktop app is closed, keep a connection to that machine open. Use the Companion app on your phone or a browser tab.

Microphone and camera on the desktop

Dictation uses the microphone and pairing by QR code uses the camera, so macOS asks for permission the first time you use each one. Allow it once and the desktop app keeps that access. To change it later, open System Settings, under Privacy & Security, and look at Microphone and Camera.

macOS and Linux launcher

Open the desktop Companion for your selected release track:

vis-agent desktop                  # use the track selected by vis-agent update
vis-agent desktop --update         # check for a release or beta update, or rebuild dev
vis-agent desktop --track release  # download and open stable for this launch
vis-agent desktop --track beta     # download and open the newest beta for this launch
vis-agent desktop --track dev      # build and open your current source checkout
vis-agent desktop --no-gateway     # open the app without the local gateway
vis-agent desktop --help

--track overrides the desktop track for one launch. It does not change your engine selection. With no installed track, a source-only checkout defaults to dev. Otherwise the default is release.

On macOS, the launcher also copies the app to /Applications when you can write there. Launchpad, Spotlight and the Dock then open the version that the launcher installed. Each track has its own copy: Vis.app, Vis Beta.app or Vis Dev.app. Each install, update or dev build refreshes the copy of its track.

The launcher never replaces an app with that name from another publisher. Before it opens the app, it closes a copy that runs from /Applications. Set VIS_APPLICATIONS_DIR to use another folder, or set it to an empty value to turn the copy off.

Release: download and reuse

On macOS and Linux, the release track chooses the universal macOS app (Apple silicon or Intel), or the Linux AppImage for x64 or ARM64. Downloads need curl and network access. On macOS, the launcher copies Vis.app from the signed disk image into your Vis cache. On Linux, it runs the AppImage with built-in extraction, so FUSE is not required. You still need a graphical desktop and the system libraries required by the app.

Later release launches reuse the cached app and do not contact GitHub. vis-agent update updates an installed release app together with the engine. So the desktop app that you open matches the runtime that you installed. It never installs an app that you do not have.

--update checks for a newer stable version and downloads it only when it is not cached. If a download or an installation step fails, the app that you selected before stays as it was. An engine update still succeeds. Retry the command, or omit --update to open the existing copy. If a cached executable is missing, Vis downloads it again automatically.

Beta: the newest published beta

The beta track downloads the desktop app from the newest published beta, the same build that vis-agent update --track beta installs. It otherwise works like release: later launches reuse the cached app, --update checks for a newer beta, and vis-agent update --track beta refreshes an installed beta app. Beta apps are kept apart from stable ones, so opening one track never removes the other's app.

If the newest beta has no app for your platform, the launcher says so and keeps any cached beta app. Open --track release instead.

Dev: build from source

On macOS and Linux, the dev track builds the web bundle and native desktop app from your selected source on every launch, including uncommitted changes. It uses the managed checkout at ~/.vis/install/src when present. Otherwise, a checkout-owned bin/vis-agent builds that checkout. It never downloads a released desktop app or falls back to an older build after a failure.

Before you run it, install these tools:

  • Node.js 20 or newer, with npm.
  • Rust 1.85 or newer, with Cargo.
  • The native build tools. macOS needs Xcode and its command-line tools. Linux needs a C/C++ toolchain, WebKitGTK 4.1 development packages and xdg-utils.

The desktop build workflow lists the Ubuntu packages. Some of these installs need administrator access. Dependency downloads need network access, and the first native build can take several minutes. Later builds reuse the npm and Rust download and build caches, but they still run the build steps.

The launcher runs npm ci, npm run build, and npm run package:desktop -- --dev in apps/vis-companion. This reinstalls that checkout's node_modules and updates its build outputs. The result targets only your machine's architecture, needs no release signing credentials, and has a separate app identity from stable. desktop --update also builds the current checkout. To fetch newer source first, run vis-agent update --track dev.

Cached files and pairing

Release files live in ~/.vis/install/desktop/<platform>/<version>/, beta files in ~/.vis/install/desktop/beta/<platform>/<version>-beta.<commit>/, and source builds in ~/.vis/install/desktop/dev/<platform>/<version>.<build>/. All of them respect VIS_HOME, and installing an app there needs no administrator access.

Only one desktop app runs at a time. A launch closes a desktop running from another version or track, then opens the version you selected. If that version is already running, its window comes to the front.

The launch then deletes the other versions in that track's folder, leaving one app on disk. The other tracks keep their files. Release and beta apps deleted this way download again when you need them, and dev builds are rebuilt from source on every launch.

A desktop launch does not change your engine track. If no local gateway runs, it starts one in the background through your installed engine. The gateway stays up while the app runs. After you quit the app, a gateway started this way stops when no other client or work remains. A gateway that you started with vis-agent gateway start keeps running.

--no-gateway opens the app alone. --gateway or VIS_GATEWAY_URL names another gateway, so a launch with either one also opens the app alone. The TUI and vis-agent web follow the same rule. A launch without an installed engine also opens the app alone.

On first launch, add this machine in the app with http://127.0.0.1:7890 and an empty bearer token. For a gateway on another machine, use its URL and bearer token. See Desktop and mobile setup for connection options.

Automatic native betas

The Beta Native workflow starts after successful push CI on main. It verifies that CI passed for the exact commit in this repository and selects the latest successful main run. A newer successful run cancels an older beta build. New commits whose CI is pending or failed do not block publication of a green beta.

Beta uses the same native build and test workflow as stable releases on Linux x86-64, Linux ARM64 and macOS ARM64. It also uses the same desktop packaging for macOS, Windows and Linux. Each build has an immutable beta-<commit> tag. Its prerelease stays a draft until two conditions are true:

  • All native tests, SDK checks, TUI checks and desktop packaging pass.
  • The six engine and TUI archives, the web app and the six desktop installers are present and not empty.

A failed or cancelled build cannot replace the last published beta. A beta never becomes the latest stable release on GitHub, and it does not publish mobile apps.

Files

Path Contents
~/.local/bin/vis-agent-native Installed native engine
~/.local/bin/vis-agent-python/ Its bundled Python worker and interpreter
~/.local/bin/vis-tui Matching native terminal client
~/.local/bin/vis-web/ Web app that the gateway serves
~/.vis/install/desktop/ Desktop apps by platform and version, with beta apps in beta/ and dev builds in dev/
~/.vis/install/track Selection for later launches
~/.vis/install/src Managed dev checkout at a detached main commit
~/.vis/install/ref Commit pinned by the last dev update
~/.vis/install/vis-agent-native Native engine for a checkout-owned launcher

Each native engine has a vis-agent-native.build file beside it, containing its version, commit, build track and timestamp. vis-agent --version reports the version. VIS_HOME changes the state directory from ~/.vis. vis-agent --measure prints startup timings. --jfr saves Java Flight Recorder profiles.

Native bundles

vis-agent-<os>-<arch>.tar.gz
├── vis-agent
├── vis-agent-native
├── vis-agent-native.build
├── vis-agent-python/
└── install-vis-agent

vis-tui-<os>-<arch>.tar.gz
└── vis-tui

To build an image, you need the GraalVM CE version in .graalvm-version and about 32 GB of RAM. bin/release-native builds and smoke-tests the assets that the host supports. On Apple silicon, it builds macOS natively, Linux ARM64 in a container and Linux x86-64 through Rosetta.

Enable Rosetta in Docker Desktop or podman, because the build rejects qemu. VIS_CONTAINER_CONNECTION and VIS_CONTAINER_CLI select the container machine and engine. On platforms without native bundles, use the dev track.

See also