Architecture
Monitoring, stripped down, is one shape: collect the data, evaluate it, see it, act on it. The point is to know your systems, and the question that matters most:
Is this system working right now?
This page follows a single reading through its whole life, gear to answer to action. Each bold word is an official term; the linked ones open their deep dive, and every one is defined in the glossary.
The fleet
Section titled “The fleet”Three nouns describe what you operate.
- A component is a deployed device, app, or service: a display, a DSP, a cloud UCC service.
- A system is a set of components that work together to do one job: a meeting room, a classroom, a broadcast chain. The word is deliberately universal: a system is the unit you actually care about, whatever shape it takes.
- A location ties systems and components to a physical place (campus, building, floor, room).
Collect
Section titled “Collect”AV gear is agentless: nothing can be installed inside it, so the reading comes from outside. Sometimes the component pushes it to Omniglass; usually Omniglass polls on an interval. Either way, a node running close to the gear reaches a component over an interface (whatever the device speaks: SNMP, HTTP, SSH, a control processor’s own command language) and reads.
How to reach a class of device, and what to read from it, is declared once in the component’s template, the reusable device shape. The node runs that and parses the answer at the edge, turning a vendor’s raw response into a normalized reading on the spot.
That normalized reading is a sample.
The sample
Section titled “The sample”A sample is one reading of one canonical signal (power-state,
audio-level), in one of two lanes: a metric is a quantity (a number that aggregates: an
average fan speed means something), a property is a value (what something is, including a
number used as a name: input 3, zone 4; values do not aggregate, they have duration). It is
owned by exactly one entity through the exclusive arc: a component or a system
or a location, never more than one. It carries a provenance (how we know it: observed
from the device, calculated by Omniglass, intended by a
command we sent, or declared by an operator) and a source
(which sensor or path told us).
The meaning of each signal (its value type, its unit, its validation) lives in a governed
catalog per lane (metric_type, property_type), and a template references a registered
signal rather than inventing one, so two displays from
different manufacturers answer the same question the same way: the measurement is named, not
the device.
What it should be
Section titled “What it should be”Not every value is measured. Some are declared, set by an operator rather than read from a
device. A declared signal value (this input should be HDMI1) is an ordinary sample row with
provenance=declared in the same series its observed side lands in, so its edit history is the
series itself; a plain variable just rides down the tree (this
system polls every 30 seconds),
resolved down a cascade: set once high, overridden exactly where it
matters. The same
cascade resolves tags (the governed label vocabulary), encrypted secrets,
and platform settings, and files attach
alongside them as searchable handles over a content-addressed blob store. A declared signal has an
observed side,
so the gap between intent and reality is drift, a signal you can alarm on or a fix you can push
back.
Detect
Section titled “Detect”An event_rule watches a sample and fires when its condition, an expression, is met, recording an event: our assertion that something happened. Pair a fire with a clear and the two events open and resolve an alarm, the stateful incident, one row per occurrence, the thing an operator works and a ticket binds to. An alarm impairs its component’s own verdict wholesale, turning a detection into a verdict on the system.
Model health
Section titled “Model health”A single alarm is rarely the point. The headline is health: a verdict on the system, carried as a calculated sample. The chain: a critical alarm takes a component’s own verdict to outage, so it no longer occupies the role it was filling (a lesser alarm degrades it but leaves it in place); a role below its quorum is impaired and contributes its declared impact (outage, degraded, or none); the system takes the worst contribution, and a location the worst of its systems. A target on that verdict over time is a real uptime SLA.
The other half is “since when”. Health is recorded as a transition, written by the change that caused it rather than by whoever opens a page, so the edges are exact weeks later.
The rollup ships opinionated by default, a first-class model rather than a byproduct of the rules engine, with an escape hatch for the systems the defaults get wrong.
An action_rule subscribes to events and alarms and runs an action. An action can be one step (notify the right person) or many (remediate, wait, re-check the real sample, escalate if it did not take; or open and close a ticket as the alarm opens and clears).
See it
Section titled “See it”The operator never queries raw tables. Reads go through views (a named
query returning a uniform {columns, rows}), rendered in the console: the
fleet-health grid, the “why did this value win” cascade explainer. The console
is one client of the API, the same contract the generated CLI and the
AI seams (MCP included) drive.
The journey, end to end
Section titled “The journey, end to end”Underneath
Section titled “Underneath”The journey rides on a few foundations:
- the Storage Gateway is the one door to the database; every read and write goes through it, which is where scope (identity and access) is enforced: a permission on every route, a visibility filter on every query. A grant can target a group of principals as well as a single one.
- the workers are one machinery: durable JetStream consumers over the messaging subject contract. The built one is the telemetry consumer; the rule engine, the clock, and reconcile follow the same shape; no bespoke loops.
- the audit trail and the operational logs are immutable, append-only ground truth: the record of who changed what and what the platform did.
- time is the one primitive that turns the passage of time into events, so the rest of the pipeline stays purely event-driven.
- scaling and deployment: the single binary is a modular monolith with run modes, deployed as one container for a small fleet or scaled out on Kubernetes with a distributed edge.
Samples are parsed and emitted at the edge, not re-derived from a raw store. Raw payloads are a debugging aid (a dev raw mode plus failure logging on collection); how much of that to persist, and for how long, is still being settled.
The invariants
Section titled “The invariants”A handful of patterns hold everywhere:
- Identity is three columns: an immutable uuid
idevery foreign key stores, a renameable operator-typednamethat URLs, CLI arguments, and topics carry, and an optionallabela human reads. A rename is a custom method (POST /components/{name}:renameand its siblings) gated on its own, so it moves one column and nothing else (ADR-0076). - Exclusive-arc ownership: every sample, event, and alarm names exactly one owner (component, system, location, or node), so system- and location-level signals are first-class.
- Templates fork, nothing pins: creating from a template is a one-time clone with no back-pointer, so a template can be rewritten in any release without migrating an install (ADR-0071).
- On-row lineage: a derived row carries its own evidence; there is no separate execution table.
- The
officialboolean: every registry (metric_type,property_type,event_type,command_type, and the catalogs) and rule row carries anofficialboolean: the curated ship-with set, seeded at boot and authoritative; the rest is operator-authored and local to a deployment. - Views by default: current-state reads are plain views, materialized only when a profile proves it necessary.
- Not event-sourced: stateful entities (alarm, action) hold their state directly.
- Per-database isolation: there is no tenant column; a tenant is a database.
Look up any term
Section titled “Look up any term”Every official term is defined once in the glossary, and the deep pages in the sidebar follow this same journey. The physical schema lives in storage, and the generated ERD over it in the data model.