Skip to content

CLI Reference

Beyond install and uninstall (see Install Vision), the vision binary wraps the rest of day-to-day operation: starting and stopping the service, checking its health, backing up and restoring data, and inspecting configuration. Each command is a thin, honest wrapper — most print the underlying systemctl or journalctl command they run (to stderr, so piped stdout stays clean), and those raw commands remain fully supported if you’d rather use them directly.

Run vision help for the full list, or vision help <command> for one command’s detail.

CommandWhat it does
vision start [--force]Validates the config, then systemctl start vision.
vision stopsystemctl stop vision.
vision restart [--force]Validates the config, then systemctl restart vision.
vision enable [--now]systemctl enable [--now] vision — start at boot.
vision disable [--now]systemctl disable [--now] vision.
vision logs [-f] [-n N] [--since W] [--until W] [-o FMT]journalctl -u vision --no-pager, with your flags. -f follows.

vision logs never needs root: journal reads work for members of the systemd-journal (or adm) group. If you see no entries, add your user to that group or run it with sudo.

CommandWhat it shows
vision status [--json] [--verbose]Unit state, the same checks /readyz runs, config/data paths and sizes, and two drift warnings: a binary that was replaced without a restart, and root-owned WAL sidecar files the service can’t write to. A License line shows the license file’s public ID, or not activated (the live state and expiry are on Settings → License).
vision doctor [--json] [--config PATH] [--db PATH]An offline checkup for a box where the service won’t start: config validation, schema/environment/keyring checks, systemd unit shape, a database integrity check and schema-version check, file ownership, free disk space, the effective enabled-workers set, the reconcile-sweep safety settings, the license file (exists, owner vision, mode 0600, granted by the unit), and whether the license servers answer (warning only — see Licensing). Every finding is paired with a fix.
vision versionPrints the binary version and build time.

Both status and doctor work without root — root-only checks are shown as skipped rather than failing. status never exits 0 while the service is down, so it’s safe to use in monitoring scripts:

Exit codeMeaning
0ok
4not installed
5unit not active
6active, but not ready

On a fresh install, status reports Not ready: no Alta server yet with the address of Settings → Connections — add a server and it turns ready.

CommandWhat it does
vision backup [--output PATH|-] [--no-secrets] [--no-maps] [--force] [--recover-wal] [--db PATH] [--config PATH]Consistent hot backup — no downtime. See Backup & Restore.
vision restore <archive> [--dry-run] [--stop-service] [--yes] [--force-key-mismatch]Verified, guarded restore. --yes accepts the host-specific prompt in scripts. See Backup & Restore.
vision reset-password <email> [--url BASE] [--config PATH] [--db PATH]Mints a one-time password-reset link for a locked-out admin. See Recover a forgotten password.
CommandWhat it does
vision config validate [--config PATH] [--env-file PATH]Checks the installed configuration exactly the way boot would — the same merge of config.yaml and the systemd env file.
vision config print [--format text|json]Prints the effective, merged configuration with every secret redacted — safe to paste into a support ticket.
vision config print --referencePrints the full annotated reference configuration (every key, its default, and a description) — no installed config needed.

Neither config subcommand needs root.

CommandWhat it does
vision install [--no-restart]Installs or upgrades the service without replacing config or secrets. A changed binary restarts an active service unless --no-restart is set.
vision uninstallRemoves the service but keeps config and data.
vision uninstall --purge [--yes] [--no-backup]Also deletes config, data, the system user, and binary. Takes a final backup and requires purge <hostname> confirmation; --yes is for scripts. Avoid --no-backup unless the data is disposable.
CodeMeaning
0success
1attempted and failed
2usage error
3precondition failed — not Linux, no systemctl, or needs root
4not installed (no unit, config, or database found)
5 / 6status only — see the table above
  • Mutating commands (start, stop, restart, enable, disable, install, uninstall, restore) check for root themselves and refuse with exit 3 rather than letting systemctl fall through to a polkit prompt — which would hang forever without a terminal (cron, CI, a pipe).
  • Read-only commands (status, logs, config, doctor) never require root; they degrade individual rows or checks instead.

The log level is fixed at boot — there’s deliberately no runtime toggle. Set it in the env file and restart:

Terminal window
echo 'VISION_LOG_LEVEL=debug' | sudo tee -a /etc/vision/vision.env
sudo vision restart

Remember to remove it afterwards — debug is verbose.

Service logs are structured JSON on stdout, which lands in journald — log rotation is journald’s job, not Vision’s. If vision logs shows the journal eating disk space, cap it in /etc/systemd/journald.conf:

[Journal]
SystemMaxUse=1G

then sudo systemctl restart systemd-journald.

Re-run the installer with the new binary — it’s idempotent (config and secrets are never overwritten) and restarts the service once the binary has actually changed:

Terminal window
curl -fsSL https://vision.cesbo.com/install.sh | sh

For a controlled maintenance window, run the newly downloaded binary without restarting, then apply it when ready:

Terminal window
sudo /path/to/new/vision install --no-restart
sudo vision restart

vision install also restarts a service still running an older copy of the binary — the one-liner moves the new binary into place first. vision status warns if the running process predates the binary on disk.

The binary has no TLS listener by design — production terminates TLS at a reverse proxy in front of it. A minimal nginx site:

server {
listen 443 ssl;
server_name vms.example.com;
ssl_certificate /etc/letsencrypt/live/vms.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/vms.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3303;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# SSE (alerts/status feeds) and long-lived requests:
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_read_timeout 3600s;
}
}

or Caddy, which handles certificates automatically:

vms.example.com {
reverse_proxy 127.0.0.1:3303 {
flush_interval -1
}
}

Then, in /etc/vision/config.yaml, add the public origin to http.allowed_origins, set http.secure_cookies: true, and run sudo vision restart. If you also set http.internal_addr for a separate metrics/health listener, don’t point the proxy’s own health check at /readyz on the public listener — see the note printed by vision status.