Control plane
How Gateway, Kernel, and Workers communicate in MDK
Overview
This page covers authenticated requests, live reads, command dispatch, and approval-gated writes. It spans the Gateway, Kernel, and Workers, but each layer owns a different responsibility.
Use this page to understand which layer receives a request, which layer validates it, and when a write becomes a command.
For package-level APIs and configuration, use the Gateway README, Kernel README, and Worker README.
Responsibility boundaries
Gateway owns the consumer-facing surface, including HTTP and plugins. It is also where authentication belongs, though it implements none:
that logic lives in the plugin controllers you write. Browser UIs and agents should enter MDK through the Gateway (they do not talk to Kernel
directly). Agents can also reach MDK over MCP through the standalone @tetherto/mdk-mcp package.
Kernel owns coordination: Worker registry, telemetry routing, health checks, command dispatch, command state, and the write-action approval modules. Kernel trusts established callers; it does not validate user identity.
Workers own hardware integration. They declare capabilities, answer Kernel-initiated telemetry and state pulls, resolve candidate write calls for approval-gated actions, and execute final commands against devices.
Connection direction
The direction of each connection is intentional:
- Consumers call the Gateway over HTTP or MCP
- The Gateway dials Kernel over Hyperswarm RPC (HRPC) through
@tetherto/mdk-client - Kernel discovers Workers, then initiates every Worker RPC
- Workers never initiate upstream calls to Kernel or the Gateway
The deployment topologies and Workers discovery model pages cover how this changes across single-process, local, and distributed deployments.
Transport identity and admission
HRPC uses encrypted Noise connections with public-key identities. Kernel's HRPC public key identifies and addresses the Kernel listener. Each caller has a separate public key that the listener receives during connection setup.
Kernel compares the caller's key with the allowlist. An empty allowlist admits any HRPC caller; a configured allowlist admits the approved callers. This transport-level check works the same way whether the processes share a host or when they communicate across a network.
Transport identity is not user identity. The HRPC allowlist controls which backend processes may connect to Kernel, and it says nothing about the person or agent behind a request. Establishing that is the job of the plugin controllers serving people, browser applications, and agents.
Request paths
Read requests
Reads usually start in a Gateway route or plugin controller, pass through services.mdkClient, and reach Kernel as registry,
capability, telemetry, or state queries. Kernel routes Worker-owned reads down to the relevant Worker and returns the result to the
Gateway. Gateway controllers can combine live Kernel data with persisted local data from services.dataProxy.
For plugin controller mechanics, use the Gateway plugins guide.
Direct commands
Direct commands are immediate writes that do not require approval. The plugin controller performs whatever validation you have written into it, then
sends a command.request to Kernel. Kernel resolves the owning Worker, validates the command against the Worker's capabilities,
and hands the command to the crash-recoverable command state machine.
For command-dispatch module details, use the Kernel README.
Approval-gated writes
Some writes are staged for approval before they become commands. This keeps direct commands available while adding a separate review path for fleet-changing actions that need operator approval.
The Gateway may expose an HTTP actions surface through plugins. Any access control on that surface is written into the controllers, since the plugin
runtime enforces none. Kernel owns ActionManager, ActionCaller, and target permission checks at the protocol layer. Those Kernel checks use the
target Worker's device family, such as miner:w or container:w, read from the authPerms array the caller sends, before resolving or approving
writes. Workers answer
write.calls.request while Kernel resolves candidate writes, then execute the final command.request after the configured vote
thresholds are met.
For implementation steps, use the write-actions how-to. For React hook names and exports, use the React adapter README.
Developer surfaces
The write-action flow is reachable from two different layers depending on where you are building.
| Layer | Package | How you call it |
|---|---|---|
| React / UI | @tetherto/mdk-react-adapter | Six hooks: useSubmitSingleAction, useSubmitPendingActions, useVoteOnAction, useCancelAction, usePendingActions, useLiveActions — call Gateway HTTP routes (plugin-provided) |
| Backend / Node.js | @tetherto/mdk-client | Methods: pushAction, pushActionsBatch, voteAction, cancelActionsBatch, getAction, getActionsBatch, queryActions — send MDK Protocol envelopes directly to Kernel |
The React hooks go through the Gateway, so whatever validation your plugin controllers perform applies to them. The mdk-client methods connect
directly to Kernel and bypass that layer entirely. Neither path gets user-level control for free: the Gateway ships no authentication, and Kernel
admits backend processes according to its HRPC transport policy, where an empty allowlist admits any caller and a configured allowlist admits
matching caller keys.
Next steps
- Build Gateway routes with the plugin guide
- Submit and approve write actions with the write-actions how-to
- Review the Kernel modules
- Review Worker capabilities in the Worker README
Next steps
Learn more about: