-
Notifications
You must be signed in to change notification settings - Fork 0
Development
Local development guide for Vantyr. The stack is a Rust/Axum/Tokio/SQLx-PostgreSQL server (the only root Cargo workspace member), a Windows/Linux Rust agent with a Tauri React settings UI, and a React 19 + TypeScript + Vite dashboard.
See also: Deployment · Configuration · Environment-template · Usage · Security
| Tool | Version | For |
|---|---|---|
| Rust toolchain | stable (rustup) |
server + agent |
| Node.js | 20 | dashboard (frontend/) and agent settings UI (agent/ui-src/) |
| PostgreSQL | 16 | server database |
For the quickest look at the UI, no Rust or PostgreSQL is needed — run the dashboard in demo mode (below).
.
├─ Cargo.toml # root workspace — only member is `server` (vantyr-server)
├─ docker-compose.yml # server + postgres for production / integration
├─ .env.example # full commented config template
├─ server/ # Rust/Axum API + serves the built dashboard
│ ├─ src/ # main.rs (router/middleware), api/, ws_*.rs, db.rs, auth.rs …
│ └─ migrations/ # 55+ SQL migrations, run at startup (embedded)
├─ frontend/ # React 19 + TS + Vite dashboard (built into static files)
└─ agent/ # Rust endpoint agent (EXCLUDED from the root workspace)
└─ ui-src/ # Tauri React settings UI
The root package.json provides convenience shortcuts: npm run dev (dashboard), npm run demo (dashboard demo mode), npm run agent:dev|build|ui.
# from the repo root
cargo run -p vantyr-server # or: cd server && cargo run- Reads config from the environment via
ServerConfig::from_env(server/src/config.rs, fail-fast validated). The simplest path is to copy.env.exampleto.envand export it, or setDATABASE_URLandADMIN_PASSWORDinline. -
DATABASE_URLmust bepostgres://…/postgresql://…. Default ispostgres://monitor:monitor@localhost:5432/monitor. Bring up just Postgres withdocker compose up -d dbif you don't have one locally. - Migrations from
server/migrations/run automatically on startup. - Listens on
LISTEN_ADDR(default0.0.0.0:9000).
Common commands (run from the repo root):
cargo fmt --all
cargo check -p vantyr-server
cargo clippy -p vantyr-server --all-targets
cargo test -p vantyr-servercd frontend
npm install
npm run dev # Vite dev server, proxies /api and /ws to localhost:9000vite.config.ts proxies /api and /ws to http://localhost:9000, so run the server alongside it (no CORS config needed).
cd frontend
npm run dev:demo # http://localhost:5173 — runs entirely on mock datadev:demo runs Vite with --mode demo on port 5173 and needs no backend or database — the fastest way to see the UI. (npm run demo from the repo root does the same thing.)
Other frontend scripts:
| Command | Does |
|---|---|
npm run build |
tsc -b && vite build — type-check + production build into dist/
|
npm run build:demo |
demo-mode production build |
npm run lint / npm run lint:fix
|
ESLint |
npm run test |
Vitest (very few tests exist today) |
npm run preview |
preview the production build |
The agent lives in agent/ and is excluded from the root Cargo workspace — always build it from its own manifest, not from the repo root. The Tauri settings UI (agent/ui-src/) must be built first because tauri-build expects its dist/ to exist.
npm --prefix agent/ui-src ci # once
npm --prefix agent/ui-src run build # build the settings UI
cargo fmt --manifest-path agent/Cargo.toml --all
cargo check --manifest-path agent/Cargo.toml
cargo build --manifest-path agent/Cargo.toml # or: cd agent && cargo buildMany agent modules are #[cfg(target_os = "windows")] (the dual-process Session-0 service + user-session companion model). Ctrl+Shift+F12 opens the settings webview; --no-ui / AGENT_NO_UI runs headless.
The agent also builds on Linux (headless direct-WS runtime). The desktop build needs X11/XCB, dbus, PipeWire, Wayland, xkbcommon and EGL dev packages — see the agent-linux job in .github/workflows/ci.yml for the exact apt-get install list. Then:
cargo check --manifest-path agent/Cargo.tomlRelease MSIs are produced with cargo xwin + WiX (agent/wix/) in .github/workflows/release-agent-windows.yml. cargo-xwin lets you target x86_64-pc-windows-msvc from Linux without a Windows host. Updater artifacts are signed with minisign (TAURI_SIGNING_PRIVATE_KEY); the MSI itself is not Authenticode-signed, so SmartScreen shows "Unknown Publisher".
.github/workflows/ci.yml runs on pull requests and pushes to main/dev:
| Job | Runner | Steps |
|---|---|---|
server (rust) |
ubuntu |
cargo fmt --all --check, cargo clippy -p vantyr-server, cargo check -p vantyr-server, cargo test -p vantyr-server
|
frontend (react) |
ubuntu |
npm ci, npm run lint*, npm run build (type-check + build) |
agent (windows) |
windows | build agent/ui-src, cargo fmt*, cargo check --manifest-path agent/Cargo.toml
|
agent (linux) |
ubuntu | install desktop build deps, cargo fmt*, cargo check --manifest-path agent/Cargo.toml
|
* fmt / clippy / lint steps are continue-on-error: true (advisory) until the tree is clean. The check/test/build steps are hard gates.
Release workflows (tag v* only): release-server-docker.yml (builds/pushes the GHCR server image), release-agent-windows.yml and release-agent-linux.yml (agent installers).
Routes are assembled in server/src/main.rs; the authoritative dashboard route list is server/src/api/mod.rs. There is no /api/v1 prefix and no OpenAPI spec — action endpoints are mostly POST .../verb.
| Path | Purpose |
|---|---|
GET /healthz |
Liveness (always allowed, even with ENFORCE_HTTPS=true). |
GET /readyz |
Readiness (includes DB check). |
GET /metrics |
Prometheus metrics when METRICS_ENABLED=true. |
POST /api/login · POST /api/logout
|
Dashboard session; login returns { csrf_token } and sets the HttpOnly session cookie. |
GET /api/auth/status · /api/auth/config
|
Session + OIDC discovery. |
GET /api/auth/oidc/login · /api/auth/oidc/callback
|
OIDC SSO. |
POST /api/agent/enroll |
Exchange an enrollment code for a per-device agent token (per-IP rate-limited via GovernorLayer). |
GET /api/integration/agents/live |
Optional JSON feed when INTEGRATION_API_TOKEN is set (Authorization: Bearer …). |
Nested under /api behind a session cookie, with a per-session CSRF token required on POST/PUT/PATCH/DELETE (header X-CSRF-Token: <csrf_token>). Major groups: agents & telemetry (/api/agents, …/info|windows|keys|urls|activity|screen|mjpeg|logs|analytics), rules & policy (/api/alert-rules, /api/agent-groups, /api/app-block-rules, /api/internet-block-rules, /api/scheduled-scripts), users & audit (/api/users, /api/audit), and settings (/api/settings/… — retention, enrollment tokens, storage, capabilities, URL categorization, 2FA).
| Path | Purpose |
|---|---|
GET /ws/agent |
Endpoint agent connection — bearer-auth'd inside the handler. Carries telemetry up (keys, window/URL focus, AFK, software, MJPEG frames) and commands down (capture, policy, run-script, power). |
GET /ws/view |
Dashboard viewer stream (requires a session when auth is enforced). Only operator/admin users may send agent-control commands; viewer users receive telemetry only. |
A third WebSocket,
GET /ws/terminal, exists in the auth-gated nest for the interactive remote-terminal feature.
| Symptom | Check |
|---|---|
| HTTP 426 / "HTTPS required" | Set ENFORCE_HTTPS=false for direct HTTP, or fix the proxy so it sends X-Forwarded-Proto: https (and trust it via TRUSTED_PROXY_CIDRS). |
| Login fails on plain HTTP |
COOKIE_SECURE=true breaks cookies when the browser isn't using HTTPS. |
/api calls 404 from the dev server |
Run vantyr-server on :9000 so Vite's proxy (/api, /ws) has a target — or use npm run dev:demo, which needs no backend. |
| "ADMIN_PASSWORD not configured" / can't log in | Set ADMIN_PASSWORD (or the legacy UI_PASSWORD) for first-user bootstrap. |
| Database errors on startup | Verify DATABASE_URL, that Postgres is running, and credentials/firewall. docker compose up -d db gives you a local one. |
| Migration checksum errors | Don't edit applied migrations. Follow the message from the server (rebuild from the same files / fix _sqlx_migrations). |
Agent won't cargo check from the root |
The agent is excluded from the workspace — use --manifest-path agent/Cargo.toml, and build agent/ui-src first. |
| Tauri build fails "frontend dist not found" | Run npm --prefix agent/ui-src run build before cargo build in agent/. |
| Dashboard tokens/colors render black |
index.css must be imported in main.tsx; the app is effectively dark-only (no light token block). |
MIT — see the LICENSE file in the repository.
Install and configure
Day to day
Integrations
Developers and security