# 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](#open-the-desktop-app) connect to
the same gateway from Windows, macOS or Linux.

## When to use

- **You are installing Vis and must choose a build.** Compare [native and
  JVM](#native-vs-jvm), then [install](#installing).
- **You want to upgrade Vis to a newer release.** See [Updating and selecting a
  track](#updating-and-selecting-a-track).
- **A fix you need is only in a beta.** [Switch to that
  version](#switching-between-versions), and back to the stable release afterwards.
- **You develop Vis or need the latest code from `main`.** Use the `dev` track, or
  [run on the JVM for one launch](#one-launch-jvm-override).
- **The gateway runs a different version than your terminal after an update.** See
  [How you learn that a newer version is
  running](#how-you-learn-that-a-newer-version-is-running).
- **You want the desktop app.** [Open the desktop app](#open-the-desktop-app) for
  your platform and release track.
- **CI or a team must stay on a tested version.** [Pin an exact
  version](#pin-an-exact-version) and [verify what you download](#verify-what-you-download).
- **A desktop fix you need is only in a beta.** Open the [beta desktop
  app](#beta-the-newest-published-beta), which stays separate from your stable app.
- **You want Vis in a browser.** [Open the web app](#open-the-web-app) that your gateway
  serves.

To add Java or Clojure code inside the engine, see [Native builds for Java and
Clojure extensions](jvm-native-image.md).

## 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

```bash
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:

```bash
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.

```bash
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.

```bash
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`:

```bash
# 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`:

```bash
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:

```bash
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

```bash
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.

```bash
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:

```bash
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.

```bash
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`.

<a id="windows-app"></a>

## Open the desktop app

1. [Download the installer from GitHub Releases](https://github.com/Blockether/vis/releases/latest)
   for your computer.
2. Install the package and open **Vis** from your application launcher.
3. [Connect to your gateway](index.md#connect-an-app) 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](https://github.com/Blockether/vis/releases). A beta package installs as the same Vis app as
the stable package. To keep your stable app, use
[`vis-agent desktop --track beta`](#beta-the-newest-published-beta) on macOS or Linux instead.

Run the gateway on the computer where your projects live: macOS, Linux, or [Linux in
WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) on Windows. For a local WSL2 gateway,
enable localhost forwarding. The [connection guide](index.md#connect-an-app) covers
both local addresses and remote pairing. [Isolated drafts](drafts.md) 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:

```bash
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](https://github.com/Blockether/vis/blob/main/.github/workflows/desktop-companion.yml)
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](index.md#connect-an-app) 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

```text
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

- [Native builds for JVM extensions](jvm-native-image.md) — only for adding Java/Clojure capabilities inside Vis.
- [Getting started](index.md#connect-an-app) — download a client and connect to your sessions.
- [Configuration](configuration.md)
