Sensors: one standard read interface — catalog, single value, history, shaped query

Every number the collector samples becomes a sensor with a stable dotted ID
(cpu.core.3.usage, fan.nct6775.fan2, fs.root.used_pct). Clients discover them
from the catalog and ask for exactly what they want, including as a shaped
query: send the object you want, get it back with the values filled in.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-19 07:04:03 -07:00
co-authored by Claude Fable 5.1
parent 01aeb226ea
commit 43bf787696
8 changed files with 673 additions and 3 deletions
+12
View File
@@ -176,6 +176,18 @@ something long in one, switch away and back, refresh — it's all still there.
the daemon's sampling clock; the chart window is always 300 samples, so 30 s at 100 ms
and 10 min at 2 s. Still to do: persistent
history (SQLite ring, e.g. 10 s × 7 days), SMART (`smartctl -j`), longer time ranges.
- **Sensors** — **step 1 shipped 2026-09-19** (`internal/sensors`,
`internal/metrics/sensors.go`, reference in `SENSORS.md`): everything measured is a
sensor with a stable dotted ID; catalog, single value (`?format=text`), per-sensor
history, and a **shaped query** where the client sends the object it wants and gets it
back filled in (GraphQL's idea without GraphQL: sensors differ per machine, so a static
schema would collapse to `sensor(id:)` anyway). `/api/metrics` and the Dashboard are
untouched so far. **Remaining, in order:** (2) read-only scoped tokens + Prometheus
`/metrics`; (3) push stream + widget library, Dashboard rebuilt on its own sensors;
(4) embeddable widget page + Glance config (Glance's `custom-api` only refetches on page
load, an `iframe` of our embed is what's live); (5) non-metric sensors — services,
SMART, ZFS, updates, containers. One sampler rate, set in one place, is part of (3):
today the open dashboard still drives it.
- **Multi-host** — **Phase 1 shipped 2026-09-18** (`internal/nodes`, `internal/tlsauto`,
`MachineSwitcher.tsx`, `Machines.tsx`). One binary, hub and spoke: a host whose
`config.json` lists `nodes` is a hub; any other is a standalone node with its full UI.