Releasing soon Vigo is in alpha and closing in on its first stable release. Expect breaking changes between releases until then — we're looking for testing partners with meaningful fleets across diverse architectures. Learn more →

Architecture

How are the pieces arranged, and what talks to what?

Vigo has three binaries and one loop. A central server (vigosrv) holds the desired state; a Rust agent (vigo) on every managed node (an envoy) pulls that state, applies it, and reports back; an admin CLI (vigocli) and an HTMX web UI drive the server's REST API. The agent always initiates — the server never reaches into a node — so envoys behind NAT or firewalls need no inbound ports.

Vigo architecture — the check-in loop

The check-in loop

Everything an envoy does happens on a fixed interval, in three steps:

  1. CheckIn — the agent calls the server over gRPC/mTLS with its UUID, a fingerprint of its current state, and its traits (auto-discovered facts: OS, hardware, packages, …). Every request is ed25519-signed against the pubkey the server stored at enrollment.
  2. Resolve → PolicyBundle — the server matches the envoy's hostname against hostcrates (first match wins), resolves roles → configcrates → resources, merges variables and per-environment overrides, builds the dependency DAG, and returns an ordered bundle. secret: references are replaced with opaque markers — plaintext never crosses the wire.
  3. Apply → ReportResult — the agent applies each resource idempotently (check before act), honors depends_on ordering and notify/subscribes triggers, fetches real secret values at apply time, and reports per-resource outcomes back to the server, which stores them.

The model is pull-based: there is no push channel from server to node for routine work. When an operator needs immediacy (a force-push, an ad-hoc task, a Scrier session), the server uses the agent's already-open stream rather than dialing in.

Why it's shaped this way

  • The agent survives a missing server. It caches the last bundle, its traits, and a results queue in an embedded LMDB store, so it keeps converging offline and flushes results on reconnect. See convergence vs compliance.
  • Files are the only source of truth. Operators edit YAML (.vgo) under the stacks; vigocli config publish validates and reloads. There is no API/UI/DB path that writes config.
  • One server scales to tens of thousands of envoys at a normal cadence (fewer at a one-second cadence, where per-check-in CPU binds first — the cadence sets the ceiling), and past that, spanner federates write-equal peers.

Where this shows up


Confidential — Alexander4, LLC. Not for redistribution.