Architecture Overview

Last updated 4 min read
Report issue

Architecture Overview#

A 10-minute tour of how GritivaCore is wired together. Audience: developers about to modify the system, ops people evaluating it, and curious users.

The canonical source for the in-depth architecture is docs/architecture/overview.md in the repo. This page is the public-facing summary.

The big picture#

TEXT
                ┌──────────────────────────┐
                │   Hosted Control Plane   │
                │   (panel.gritiva.com)    │
                │   FastAPI + Postgres     │
                └────────────┬─────────────┘
                             │ outbound WebSocket (always 443)
              ┌──────────────┼──────────────┐
              │              │              │
         ┌────▼────┐    ┌────▼────┐    ┌────▼────┐
         │   VM    │    │   VM    │    │   VM    │
         │ +agent  │    │ +agent  │    │ +agent  │
         │         │    │         │    │         │
         │ scope1  │    │ scope1  │    │ scope1  │
         │ scope2  │    │ scope2  │    │ scope2  │
         └────┬────┘    └────┬────┘    └────┬────┘
              │              │              │
              └──── gmesh ───┴──── gmesh ───┘
                  (WireGuard, peer-to-peer)

Three layers:

  1. Hosted control plane — the panel, API, and docs system. Knows what should be true. Doesn't carry your traffic.
  2. The agent — a single PyInstaller binary running as a systemd unit on each VM. Reconciles its local state with the control plane's desired state.
  3. The data plane — gmesh (WireGuard between scopes), runs entirely on your hardware. We cannot see or relay your traffic.

Components#

Control plane#

ComponentTechWhat it does
APIFastAPI (Python 3.12)REST + WebSocket endpoints, RBAC, audit logs
PanelReact 19 + ViteThe admin UI at panel.gritiva.com
DatabasePostgres 15 + AlembicTenants, accounts, VMs, scopes, services, sharing, audit
WorkersCelery + RedisBackground jobs (DRM reconciler, mesh peer roster, billing)
Docs systemFastAPI + Celery + Next.jsThe thing you're reading right now

Agent (on each VM)#

ModulePathWhat it does
Main loopagentNew/main.pyEvent loop, WS connection to control plane
CollectorsagentNew/collectors/*.pyPeriodic snapshots: cpu, mem, network, services
Scope handleragentNew/handlers/scope.pyCreates/destroys netns + cgroup
Mesh handleragentNew/handlers/mesh.pyManages wg-gmesh interface per scope
Firewall handleragentNew/handlers/mesh_firewall_handler.pynftables rules in scope netns
Resource monitoragentNew/resource_monitor.pyHeartbeat + watchdog

The mesh (gmesh)#

  • Protocol: WireGuard
  • Daemon: gmeshd (one per VM)
  • Topology: full mesh between scopes (no central relay)
  • Discovery: peer roster pushed from control plane via WS
  • Identity: each scope has a long-lived X25519 keypair

Data flows#

"I provisioned a new VM"#

  1. You click "Add VM" in the panel → control plane mints an enrollment token
  2. You run curl ... | bash on the VM → installer drops the agent binary + systemd unit + token
  3. Agent starts, opens WS to panel.gritiva.com, presents the token
  4. Control plane registers the VM, sends back the initial desired state (no scopes yet, no mesh peers)
  5. Panel shows the VM online within ~10 seconds

"I created a scope"#

  1. You run gritivactl scope create my-app --cpu 2 --mem 4G
  2. Panel saves the desired state (scopes table)
  3. Agent receives a scope_create message over WS
  4. Agent calls scope_handler.py:create():
    • ip netns add my-app
    • cgcreate -g cpu,memory:my-app
    • Set quotas
    • Optionally bind /etc/resolv.conf
  5. Agent reports back scope_status: ready
  6. Panel marks the scope ready

"I shared a service from scope A to scope B on another VM"#

  1. You run gritivactl share allow --service db --to my-app
  2. Control plane writes a sharing rule, computes the implied mesh peers (A↔B), pushes to both agents
  3. Each agent's mesh.py handler:
    • Adds the peer to its scope's wg-gmesh peer list
    • Updates nftables firewall in the scope netns
  4. Inside scope B, db.scope-a:5432 now resolves and routes via WireGuard

What the agent does NOT do#

  • It does not phone home with your application data
  • It does not require root all the time (only CAP_NET_ADMIN + CAP_SYS_ADMIN)
  • It does not auto-update without your consent (you opt in via the panel)
  • It does not run customer workloads in its own process (each scope is independent)

Failure model#

FailureWhat happens
Agent crashessystemd restarts it; scopes keep running because they're separate processes
Control plane unreachableAgent retries WS with exponential backoff; existing scopes + mesh unaffected
Network partition between two VMsAffected mesh peers move to PEER_STATUS_CONNECTING, reconnect on heal
VM diesScopes on it die with it; on reboot, agent reconciles from the desired state

Further reading#