- infrastructure/proxmox/: CT provisioning configs - infrastructure/fabric/gitops/: GitOps layer - fleet.yaml: GPU inventory (Dell GTX 1050 vfio-pci passthrough) - firmware/: ESP32 firmware tree (67 files, 6.9MB) - realms/savearth/: Savearth team realm with heteronyms - lab-gateway: ESP client + manager - CI: Forgejo + GitHub Actions workflows Co-authored-by: Álvaro de Campos <campos@portugalfuturista.org>
4.5 KiB
Telemetry Ingest API — Bare-Metal Backend Spec
Version: 1.0 Target: Any HTTP-capable 32-bit CPU with MMU/MPU (ARM Cortex-A, RISC-V, x86) Runtime: Rust (Axum) or C++ (CivetWeb) — NO Python on bare metal.
Purpose
Single HTTP endpoint that receives telemetry from ALL surfaces:
| Surface | Language | How it reaches this endpoint |
|---|---|---|
| Bare-metal agent (ESP32, STM32, RISC-V) | C++/Rust/Zig/Go | HttpTransport::transmit() POSTs JSON |
| aurelio-vscode extension | TypeScript | HttpTransport (fetch) POSTs JSON |
| aurelio-theia backend | TypeScript | HttpTransport (axios/fetch) POSTs JSON |
| Python data-sharing CLI | Python | http transport POSTs JSON |
| Web portal (aurelio-web) | TypeScript | Same HttpTransport from @aurelio/shared |
All surfaces produce the SAME JSON envelope (WIRE_FORMAT.md, schema_version 1).
Endpoints
POST /api/telemetry/ingest
Receives a telemetry payload. Validates schema. Stores for aggregation.
Request headers:
Content-Type: application/json
X-Aurelio-Source: <source-identifier> (e.g. "vscode", "theia", "esp32-s3-01", "cli")
X-Aurelio-Transport: http
Authorization: Bearer <token> (optional, per-client)
Request body — the wire format envelope (see WIRE_FORMAT.md):
{
"schema_version": 1,
"collected_at": "2026-07-30T17:00:00Z",
"device_id": "esp32-s3-01",
"platform": "esp-idf v5.5.4",
"consent": {
"categories": ["tool_calls", "environment"],
"retention_days": 90,
"redact_secrets": true
},
"environment": { "os": "FreeRTOS", "chip": "ESP32-S3" },
"tool_calls": [...],
"_summary": { "environment": 1, "tool_calls": 3 }
}
Response:
202 Accepted— payload valid, queued for storage400 Bad Request— invalid schema (missing required fields, wrong version)401 Unauthorized— bad/missing token (when auth is required)413 Payload Too Large— body exceeds size limit (default 64KB)
Validation rules:
schema_versionMUST be1collected_atMUST be a valid ISO 8601 timestampdevice_idMUST be a non-empty stringconsentMUST be present with acategoriesarray- Every top-level category key MUST be in
consent.categories(no unconsented data) - Body size MUST NOT exceed 64KB (bare-metal friendly)
GET /api/telemetry/health
Health check. Returns {"status":"ok","uptime_s":<seconds>}.
GET /api/telemetry/stats
Aggregate stats (for dashboards). Returns counts per source, per category, per day.
Storage
On bare metal, payloads are stored in a ring buffer on flash/NVRAM. On server-class targets (Linux), payloads go to SQLite or append-only JSONL.
Storage layout (JSONL, one line per payload):
/data/telemetry/2026-07-30.jsonl
/data/telemetry/2026-07-31.jsonl
Retention: consent.retention_days (default 90). Older files are deleted
by a background task (on server) or on boot (bare metal).
Implementation Targets
Rust (Axum) — primary
Single binary, ~2MB static. Targets: ARM Cortex-A (Linux), RISC-V (Linux), x86_64 (Linux). Can also run as a service on Proxmox CTs.
[dependencies]
axum = "0.8"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
C++ (CivetWeb) — minimal footprint
Single binary, ~500KB. Targets: ARM Cortex-A (Linux), RISC-V (Linux), x86 (Linux). For constrained environments where Rust toolchain is unavailable.
Go (TinyGo) — microcontroller
For ESP32/STM32 with networking (WiFi/Ethernet). Runs the ingest endpoint directly on the device — peer-to-peer telemetry without a server.
Deployment
| Target | How |
|---|---|
| Proxmox CT | systemd service, binary at /usr/local/bin/aurelio-telemetry-ingest |
| Docker | docker run -p 8080:8080 aurelio/telemetry-ingest |
| Bare metal (Yocto) | bitbake aurelio-telemetry-ingest — systemd unit |
| ESP32 (TinyGo) | tinygo flash -target=esp32-coreboard-v2 ./cmd/ingest |
| STM32 (Rust) | probe-rs run --chip STM32F407VGTx target/thumbv7em-none-eabihf/release/ingest |
Relationship to existing infra
This endpoint REPLACES the Proxmox-hardcoded sync.py --push for telemetry.
The old POST /api/brain/push endpoint (Gabinete daemon) remains for brain
session sync — this new endpoint is for the consent-gated telemetry stream.
Before: device → sync.py --push → ssh root@192.168.0.38 → pct push → CT 208
After: device → POST /api/telemetry/ingest → any backend (bare metal, CT, Docker)