Running a gateway
Run a gateway when you want the Vis app, your scripts and other clients to share one agent service. The gateway owns sessions and runs tools on its machine; clients send requests and follow progress. You can run it in your terminal or keep it running under a service manager.
Install the runtime
On the machine that will run the agent, install the native release:
curl -fsSL https://github.com/Blockether/vis/releases/download/installer/install-vis-agent | bash
The installer places vis-agent and its companion runtime files under
~/.local/bin. Put that directory on PATH, then check vis-agent --version.
Native releases do not require Java; the Python SDK package alone is not an
engine installation. See
Runtime distributions for supported platforms, release
tracks and updates.
Run Vis interactively once as the account that will own the service. Configure a provider and model, complete any sign-in and try a task in the intended project. The service needs that account's configuration, credentials, writable state directory and access to the project. Connecting from a laptop does not transfer the laptop's files or credentials to the server.
Start a local gateway
Choose an unused port and start the gateway in a terminal:
vis-agent gateway start --host 127.0.0.1 --port 7890 --require-token
This runs in the foreground until you stop it; leave the terminal open. In
another terminal, run vis-agent gateway status, then connect your
Python or
JVM program to http://127.0.0.1:7890.
If a gateway is already running, check its status and port before starting
another; do not stop a shared gateway just to try an example.
--require-token enables authentication even on loopback. The default token
file is ~/.vis/gateway.token and is restricted to its owner; --token-file
selects another location. Treat this token as access to an agent that can run
tools. Keep it out of source control, logs, screenshots and command arguments.
The CLI can use the local token automatically; an SDK client needs its documented
connection settings.
An automatically started gateway can exit when it has no clients or active
work. Explicit gateway start is different: it stays running without clients,
which is the mode to use under a supervisor.
Connect from another machine
For a remote client, use a trusted VPN, an SSH tunnel or HTTPS with a trusted certificate. Do not send bearer tokens over plain HTTP on an untrusted network. Keep the gateway bound to loopback when a tunnel or reverse proxy provides the remote entry point.
For example, forward a local port to a gateway on your server:
ssh -N -L 7891:127.0.0.1:7890 visgw@gateway.example.com
Keep that tunnel open and point the SDK at http://127.0.0.1:7891. Authentication
is still required. For HTTPS, use an origin such as https://gateway.example.com
with no path prefix if you use the Python SDK. Your proxy must forward
authorization headers and let server-sent events stream without buffering or
short idle timeouts.
Supply the token through your application's secret configuration. Pairing links and QR codes also contain connection credentials: generate or view them only in a private terminal, and do not use them as public examples. See remote app connections for pairing the Vis app.
Keep it running on Linux
A service manager should own a foreground gateway, not a Python program
that repeatedly calls LocalEngine. LocalEngine is for a private child
process with temporary session history, not a persistent HTTP service.
The following systemd example uses an account named visgw. Before enabling
it, create that account, install Vis for it, prepare /srv/vis-project and
complete provider setup as that account. The account must own its state
directory and have only the project permissions it needs. Adapt paths to your
machine; installing a unit alone does not prepare these prerequisites.
Save the unit as /etc/systemd/system/vis-gateway.service:
[Unit]
Description=Vis agent gateway
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=visgw
Group=visgw
WorkingDirectory=/srv/vis-project
Environment=HOME=/home/visgw
Environment=PATH=/home/visgw/.local/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/home/visgw/.local/bin/vis-agent gateway start --host 127.0.0.1 --port 7890 --require-token
Restart=on-failure
RestartSec=5
TimeoutStopSec=60
UMask=0077
[Install]
WantedBy=multi-user.target
Enable it only when you are ready to start a persistent service:
sudo systemctl daemon-reload
sudo systemctl enable --now vis-gateway.service
sudo systemctl status vis-gateway.service
sudo journalctl -u vis-gateway.service -n 50 --no-pager
You should see an active service and a listening gateway, not a repeating restart
loop. Run vis-agent gateway status as the service account to inspect the same
local gateway. Avoid exporting VIS_GATEWAY_URL or VIS_GATEWAY_TOKEN into the
service: those select a remote target for clients, not the listener's address.
Keep the complete native bundle together. Its launcher sets up the Python
sidecar; copying only vis-agent-native can leave a process that starts but
cannot run Python tools. A custom launcher must preserve the bundle layout and
runtime environment. Prefer the supplied wrapper unless you maintain and test
that setup yourself.
Operate a small server
Use prebuilt native releases on a small VPS; compile native images on a larger builder for the target operating system and architecture. A native engine does not eliminate the memory used by Python workers, extensions or commands the agent starts. Begin with modest concurrency and monitor memory under your real workload; see resource limits.
The service account's ~/.vis holds persistent configuration and history.
Protect its backups and leave room for databases, attachments, logs and project
builds. Do not store it in a replaceable release directory. VIS_HOME controls
launcher installation state; it does not relocate all engine configuration.
Use a separate OS account for a separate service's home and credentials.
Before an update, review the update behavior and check for
active work. vis-agent update --keep-gateway leaves the running gateway alone;
the new runtime is used after a planned restart. Restarting a service can
interrupt requests and tools, so do it in a maintenance window, not on every
client connection.
Troubleshoot a connection
| Symptom | Check |
|---|---|
| Connection refused | Service state, listener port, tunnel and firewall |
| Authentication fails | The token belongs to this gateway and is passed to the client; never print it to debug |
| Client reports an incompatible protocol | Update the SDK and gateway to compatible versions |
| Requests work but progress stalls | Proxy SSE buffering, idle timeouts and the client's transport timeout |
| Python tools fail after a manual install | The launcher, Python sidecar, file permissions and service environment |
| A session cannot find the project | The path exists and is accessible on the gateway machine |
Stopping a shared gateway affects every client. vis-agent gateway stop --if-idle
requests an idle-only stop; vis-agent gateway stop can interrupt active work.
For a supervised service, use the service manager for an intentional stop so its
restart policy does not undo your action.
Collect evidence when work stops progressing
Vis saves a JSON report before the gateway watchdog cancels a stalled turn or gives up on a cancellation. A running local CLI client can also capture JVM threads when the gateway stops answering.
Reports live under ~/.vis/logs/YYYY-MM-DD/gateway-hang-<id>/, using the UTC
capture date. See Hang reports for contents, collection
limits and client-side paths, and retention
for cleanup rules. Review the files before sharing them.
See also
- Python SDK — connect a script or wrap an owned local agent.
- Java and Clojure SDK — connect a JVM application.
- Native builds for JVM extensions — only when adding Java/Clojure capabilities to the engine.
- Process jail and network policy — limit what the service's tools can access.
