Architecture
FourEyes is a single central server that many probe nodes dial into. One server binary, one node binary, one bidirectional mTLS stream per node.
┌─────────────────────────────────────────────┐ │ Central server (Go) │ │ gRPC + grpc-gateway (REST) · React UI │ │ ring buffer → flush → time-series store │ │ control-plane stream registry + scheduler │ │ alert engine · correlator · metrics taps │ └──────────────────▲──────────────────────────┘ │ one outbound mTLS gRPC stream each ┌────────────────────┼────────────────────┐ │ │ │ ┌───┴────┐ ┌───┴────┐ ┌───┴────┐ │ node │ │ node │ │ node │ └────────┘ └────────┘ └────────┘Components
Section titled “Components”Server
Section titled “Server”A single Go binary that:
- Terminates node mTLS gRPC connections and reverse-proxies REST via grpc-gateway.
- Hosts the React UI (built by Vite, embedded at release).
- Buffers incoming results in a ring buffer, then flushes in batches to the time-series store.
- Runs the control plane: the node/stream registry, test assignments, and a full resync on reconnect (plus diff-at-write on change).
- Hosts the alert engine, the event correlator, and the observability taps
(Prometheus
/metrics, OTLP metrics/traces, live SSE).
A single Go binary that:
- Holds an outbound mTLS bidi stream to the server and reconnects automatically.
- Runs an in-process scheduler driving a closed executor registry.
- Buffers to local disk (bbolt) so results survive a transient disconnect.
- Optionally self-updates: downloads an ed25519-verified binary, swaps atomically, and re-execs.
foureyesctl
Section titled “foureyesctl”A GitOps CLI that declares tests, alert rules, and dashboards as YAML and
reconciles them against the live server (apply / diff / export). See
GitOps.
Data path
Section titled “Data path”- Connect — each node opens one mTLS gRPC stream and stays connected.
- Assign — the server pushes test assignments down the stream; nodes resync on reconnect.
- Probe — nodes run scheduled tests through the closed executor registry and stream results up.
- Ingest — results enter a ring buffer, flush in batches to the time-series store, and fan out to every consumer.
- Act — the alert engine, correlator, live SSE stream, Prometheus endpoint, and OTLP exporter all tap the same flush (no re-querying the store).
One source of truth
Section titled “One source of truth”Every wire shape — node protocol, REST API, TypeScript client, OpenAPI document —
is generated from protobuf under proto/foureyes/<ctx>/v1/. There is no
hand-maintained parallel schema to drift.
Storage
Section titled “Storage”- Relational store: SQLite by default (goose migrations), explicit
Scopeon every method for tenant isolation. - Time-series store: pluggable. SQLite TS (pure Go, default) or DuckDB (CGO
opt-in,
-tags duckdb). A sharedstoretestsuite proves both behave identically.
See Storage & configuration and the security model for more.