The contract between the Axyr engine and its consumers — the dashboard (human UI) and AI agents. It defines one shape: the system snapshot, a JSON object describing an embedded system's real state.
- Formal schema:
system-snapshot.schema.json(JSON Schema 2020-12). - Example (real capture):
system-snapshot.example.json.
Build the dashboard against the schema; the example shows a populated snapshot.
schema_version is 1.0. The snapshot shape is stable; changes are additive
(new optional fields/sections). The engine implements the get_snapshot MCP
tool, which returns this whole object as JSON in one call — the one-call endpoint
for the dashboard. (Per-section tools that return human text also exist; see
actions.) The variables section is populated from the AXYR_WATCH
environment variable (comma-separated global names). Both the canonical example
and the live get_snapshot output validate against the schema.
| Field | Type | Notes |
|---|---|---|
schema_version |
string | "1.0". |
captured_at |
string | ISO-8601 UTC. |
device |
object | Target identity. |
state |
object | Current core state. |
system_map |
object | Static hardware map. |
threads |
array | Live RTOS threads (may be empty). |
timeline |
array | Recent context switches. |
variables |
array | Watched globals. |
peripherals |
array | Decoded peripheral state (on demand). |
crash |
object | null | Last crash post-mortem. |
actions |
array | What an agent can do (MCP tools). |
- device —
board,chip,core,cpuid,probe,transport. - state —
core(running/sleeping/halted/crashed/unknown),summary,reset_reason(from RCC flags),clocks. - system_map —
source,devices(a tree of{label, kind, compatible, address, status, children}),disabled.kindis a human category (led,sensor,i2c bus,uart,gpio,clock,core, …). Addresses are hex strings;nullwhen the node has none. - threads — per thread:
name,stack_used/stack_total/stack_pct(bytes/%),cpu_pct. Empty on bare-metal. - timeline — context switches oldest-first:
{cycles, thread}("what ran when").cyclesare CPU cycles. - variables — watched globals:
{name, address (hex), type, value}. - peripherals — decoded registers:
{name, address, registers:[{name, value (hex), fields:[{name, value, meaning}]}]}.meaningis the SVD symbolic name when defined. Read-side-effect registers are omitted (non-intrusive). - crash —
cause,reason_code,fault_address,location({function,file,line}),call_stack(frames),registers,recent_telemetry.nullif no crash recorded. - actions —
{name, kind: read|action, args}for each MCP tool.
The snapshot shape is stable across OSes/boards/architectures; only the producers differ per backend:
- OS-agnostic (any RTOS / bare-metal):
device,state.clocks/reset_reason,peripherals,variables,crash.registers,actions. These come from the silicon (SWD/SVD/ELF). - Backend-provided (Zephyr today; FreeRTOS/bare-metal later may fill these
differently or leave them empty):
system_map(devicetree),threads(thread analyzer),timeline(tracing),crashcall-stack symbolication.
A consumer should treat backend-provided arrays as possibly empty and render what's present.
- Non-intrusive: producing a snapshot never halts the core (RTT is buffered; SWD reads run in background; the coredump is read from RAM after a fault).
- Deterministic: transient probe glitches are retried; values reflect the
real device state at
captured_at.