MDK Logo

Architecture

How Gateway, Kernel, and Workers fit together, who owns what, and how one command travels end to end

How MDK works

MDK is built around ownership, not layers. Three tiers, each owned differently:

  • Kernel is invariant. One small coordination layer every deployment runs unchanged: it routes validated commands to whichever Worker owns a device, and pulls telemetry back. It has no plugin system and no per-deployment configuration of its routing behavior.
  • Extensions are yours. Worker plugins wrap a device family; Gateway plugins add HTTP routes, aggregation, and auth. Both are code you write and own, isolated from the kernel and from each other.
  • The UI devkit is optional. Nothing above the Gateway is required: a deployment can dispatch commands and pull telemetry with only @tetherto/mdk-client and no Gateway or UI at all.

The round trip

One request, traced end to end: an AI agent or a dashboard calls a Gateway plugin's route. That plugin builds its own @tetherto/mdk-client and dispatches a command through it. Kernel resolves which Worker owns the target device, forwards the command over the Worker's own connection, and relays the result back through the same path: Gateway plugin, then caller. Telemetry travels the same round trip in reverse, on demand: the Gateway plugin's client asks Kernel for a device's telemetry, Kernel forwards that pull to the owning Worker and relays the answer straight back. Kernel also runs its own scheduled telemetry/health pulls on a fixed cadence, independent of any caller: the two are separate triggers into the same path, not one waiting on the other.

Both extension points sit at the edges of this trip, never in the middle: a Worker plugin teaches Kernel about one device family; a Gateway plugin teaches the Gateway a new route. Kernel itself never changes.

The three tiers

Gateway: a container that hosts plugins and exposes them over HTTP. It is the active side of the Kernel connection (it dials Kernel, never the reverse) and the only tier where user-level authentication, aggregation, and business logic live. Kernel's own allowlist, when configured, gates which connections it accepts: a transport-level check, not a user identity.

Kernel: the passive coordination layer. It never initiates contact with a caller; it discovers Workers, routes commands to the one that owns a device, and pulls telemetry and health on its own cadence. It performs no aggregation and stores no telemetry itself.

Workers: the integration handlers between physical hardware and Kernel, and the source of truth for that hardware's state. A Worker answers only when Kernel asks (identity, capabilities, telemetry, or a command) and never calls Kernel unprompted.

Why HRPC

Every hop above (Gateway to Kernel, Kernel to Worker) speaks Hyperswarm RPC (HRPC): an encrypted, key-addressed peer-to-peer transport, not HTTP. A site network connects a fixed, known set of processes to each other, not the open web; HRPC's key-based addressing means a Worker or Gateway is reachable the same way whether it sits on the same host or across a DHT, with no separate TLS/cert story and no public-facing port to secure. The trade-off is a caller must hold or discover the callee's public key before it can connect: there is no URL to type into a browser.

In practice: a caller sends one request and receives one response over that channel; telemetry is never pushed to a caller or streamed: it is always a pull, whether triggered on demand by a caller or by Kernel's own scheduled cadence, and read back through the same round trip described above. A dropped connection is the client's problem to recover from: the next call through @tetherto/mdk-client reconnects; Kernel does not buffer or replay what it couldn't deliver while the link was down.

What's authoritative, and what's cached

Kernel's own store holds only its Worker registry, device capabilities, and the write-command log: never telemetry. Telemetry is Worker-owned: a Worker persists its own device history, and every telemetry read anywhere above it (Gateway plugin, dashboard, agent) is a live pull through that chain, not a read from a Kernel-side cache. See the storage model for the full picture, including what Kernel's write-command log guarantees on restart.

Next steps

Next steps

On this page