Building on MDK
MDK is a P2P mining device management platform layered as:
Consumers → Gateway → Kernel (a.k.a. ORK) → Workers → Devices.
The Kernel (backend/core/kernel) discovers workers over the Hyperswarm DHT,
pulls telemetry, dispatches commands, and monitors health. Workers
(backend/workers/) are device-protocol adapters: a Worker Plugin, either
a directory-loaded package (mdk-contract.json + src/ handlers, hosted on
WorkerRuntimeV2 — the shape mdk create worker scaffolds) or the older
{ contract, dir, connect } + handler-module shape hosted on the generic
WorkerRuntime (backend/core/mdk-worker; both shapes are documented in
../mdk-worker-plugin/references/worker-base-api.md).
All Kernel ↔ Worker communication is MDK Protocol envelopes over
@hyperswarm/rpc — never direct method calls.
Load references/architecture.md when you need the module-level picture, and
references/protocol.md before touching anything that sends or receives
envelopes. references/package-index.md maps every package name to its actual
folder. references/glossary.md decodes the terminology.
Route to the right skill
Skills are installed as flat siblings — each row names a skill directory next
to this one. Read this table first on every MDK task; many user prompts
need more than one skill in order.
Single-skill tasks
| If the task is… |
Use skill |
Read first |
| Integrate a new device (miner, power meter, sensor, container) |
mdk-worker-plugin |
references/protocol.md |
| Add / change a Gateway aggregation HTTP endpoint only |
mdk-gateway-plugin |
worker mdk-contract.json |
Build a UI page/widget for an existing /api/... route |
mdk-ui-component |
mdk-ui-component/references/ui-registry.json |
Deploy / run / register plugins in mdk.yaml |
mdk-deployment |
project mdk.yaml |
Composite prompts (use multiple skills, in order)
Prompts like "create a UI to show <metric> for a <device>" are
not UI-only. Follow this chain:
| Step |
Skill |
What you do |
| 1 |
(discovery) |
Resolve each mdk.yaml → spec.workers[].package to its mdk-contract.json at the package root (or legacy plugin/mdk-contract.json); confirm the telemetry channel, unit, and brand/fingerprint exist |
| 2 |
mdk-gateway-plugin |
If no Gateway route returns that shaped metric, mdk create plugin <name> (scaffolds + registers under mdk.yaml → gateway.plugins) then write the controller + mdk-plugin.json |
| 3 |
mdk-deployment |
Restart gateway/worker as needed |
| 4 |
mdk-ui-component |
Hook (useQuery) → presentational panel → thin page → routes.ts; props from ui-registry.json only |
| 5 |
mdk-deployment |
Verify with curl + running dashboard |
Skip step 2–3 when the route already exists and returns the right JSON.
Skip step 1's device work — if the worker/channel is missing, insert
mdk-worker-plugin before step 2.
User: "show / UI / dashboard for <metric> on <device family>"
│
▼
Contract exists? ──no──► mdk-worker-plugin ──┐
│ yes │
▼ ▼
/api route exists? ──no──► mdk-gateway-plugin ──► mdk-deployment
│ yes │
▼ ▼
mdk-ui-component ◄──────────────────────────┘
│
▼
mdk-deployment (smoke: curl + UI)
Quick examples
| User says |
Skills (ordered) |
| "Create a UI to show <metric> for <device family>" |
discover contract → mdk-gateway-plugin → mdk-deployment → mdk-ui-component |
| "Add a fleet-wide rollup API" |
mdk-gateway-plugin → mdk-deployment |
"Chart the existing /api/... in the dashboard" |
mdk-ui-component |
| "Integrate a new Modbus meter" |
mdk-worker-plugin |
| "Start kernel + worker + gateway" |
mdk-deployment |
Non-negotiable invariants
- Workers never call the Kernel. The protocol is unidirectional: the
Kernel pulls (
telemetry.pull, state.pull, health.ping) and pushes
commands (command.request). A worker only ever answers handleRequest.
mdk-contract.json is the single source of truth for a worker's
telemetry, commands, health states and error codes. Validate it against
references/mdk-contract.schema.json (the Kernel terminates workers whose
capability payload is malformed, and rejects commands not declared in it).
- Never add transport-level envelope fields. The envelope is exactly
{ id, version, type, action, sender, target, deviceId, timestamp, payload }
— extend payload instead.
- Use canonical
@tetherto/mdk-* names only — the full list lives in
references/package-index.md.
- Never invent UI prop names or telemetry fields — registry + contracts
only (
mdk-ui-component / mdk-gateway-plugin).
1---2name: mdk3description: Build on the MDK (Mining Device Kit) platform. Use whenever a task mentions MDK, the Kernel/ORK, a worker, a Worker Plugin, mdk-contract.json, @tetherto/mdk-* packages, a miner / power meter / sensor / container integration, a cross-worker aggregation endpoint, a UI component for worker/plugin data, or deploying an MDK stack.4license: Apache-2.05---67# Building on MDK89MDK is a P2P mining device management platform layered as:10**Consumers → Gateway → Kernel (a.k.a. ORK) → Workers → Devices**.1112The Kernel ([`backend/core/kernel`](../../../../../backend/core/kernel/README.md)) discovers workers over the Hyperswarm DHT,13pulls telemetry, dispatches commands, and monitors health. Workers14([`backend/workers/`](../../../../../backend/workers/README.md)) are device-protocol adapters: a **Worker Plugin**, either15a directory-loaded package (`mdk-contract.json` + `src/` handlers, hosted on16`WorkerRuntimeV2` — the shape `mdk create worker` scaffolds) or the older17`{ contract, dir, connect }` + handler-module shape hosted on the generic18`WorkerRuntime` ([`backend/core/mdk-worker`](../../../../../backend/core/mdk-worker/index.js); both shapes are documented in19[`../mdk-worker-plugin/references/worker-base-api.md`](../mdk-worker-plugin/references/worker-base-api.md)).20All Kernel ↔ Worker communication is MDK Protocol envelopes over21`@hyperswarm/rpc` — never direct method calls.2223Load [`references/architecture.md`](./references/architecture.md) when you need the module-level picture, and24[`references/protocol.md`](./references/protocol.md) before touching anything that sends or receives25envelopes. [`references/package-index.md`](./references/package-index.md) maps every package name to its actual26folder. [`references/glossary.md`](./references/glossary.md) decodes the terminology.2728## Route to the right skill2930Skills are installed as flat siblings — each row names a skill directory next31to this one. **Read this table first** on every MDK task; many user prompts32need more than one skill in order.3334### Single-skill tasks3536| If the task is… | Use skill | Read first |37| --- | --- | --- |38| Integrate a new device (miner, power meter, sensor, container) | `mdk-worker-plugin` | [`references/protocol.md`](./references/protocol.md) |39| Add / change a Gateway aggregation HTTP endpoint only | `mdk-gateway-plugin` | worker `mdk-contract.json` |40| Build a UI page/widget for an **existing** `/api/...` route | `mdk-ui-component` | [`mdk-ui-component/references/ui-registry.json`](../mdk-ui-component/references/ui-registry.json) |41| Deploy / run / register plugins in `mdk.yaml` | `mdk-deployment` | project `mdk.yaml` |4243### Composite prompts (use multiple skills, in order)4445Prompts like **"create a UI to show \<metric\> for a \<device\>"** are46**not** UI-only. Follow this chain:4748| Step | Skill | What you do |49| --- | --- | --- |50| 1 | *(discovery)* | Resolve each `mdk.yaml` → `spec.workers[].package` to its `mdk-contract.json` at the package root (or legacy `plugin/mdk-contract.json`); confirm the telemetry channel, unit, and brand/fingerprint exist |51| 2 | `mdk-gateway-plugin` | If no Gateway route returns that shaped metric, `mdk create plugin <name>` (scaffolds + registers under `mdk.yaml` → `gateway.plugins`) then write the controller + `mdk-plugin.json` |52| 3 | `mdk-deployment` | Restart gateway/worker as needed |53| 4 | `mdk-ui-component` | Hook (`useQuery`) → presentational panel → thin page → `routes.ts`; props from [`ui-registry.json`](../mdk-ui-component/references/ui-registry.json) only |54| 5 | `mdk-deployment` | Verify with `curl` + running dashboard |5556Skip step 2–3 when the route already exists and returns the right JSON.57Skip step 1's device work — if the worker/channel is missing, insert58`mdk-worker-plugin` **before** step 2.5960```61User: "show / UI / dashboard for <metric> on <device family>"62 │63 ▼64 Contract exists? ──no──► mdk-worker-plugin ──┐65 │ yes │66 ▼ ▼67 /api route exists? ──no──► mdk-gateway-plugin ──► mdk-deployment68 │ yes │69 ▼ ▼70 mdk-ui-component ◄──────────────────────────┘71 │72 ▼73 mdk-deployment (smoke: curl + UI)74```7576### Quick examples7778| User says | Skills (ordered) |79| --- | --- |80| "Create a UI to show \<metric\> for \<device family\>" | discover contract → `mdk-gateway-plugin` → `mdk-deployment` → `mdk-ui-component` |81| "Add a fleet-wide rollup API" | `mdk-gateway-plugin` → `mdk-deployment` |82| "Chart the existing `/api/...` in the dashboard" | `mdk-ui-component` |83| "Integrate a new Modbus meter" | `mdk-worker-plugin` |84| "Start kernel + worker + gateway" | `mdk-deployment` |8586## Non-negotiable invariants8788- **Workers never call the Kernel.** The protocol is unidirectional: the89 Kernel pulls (`telemetry.pull`, `state.pull`, `health.ping`) and pushes90 commands (`command.request`). A worker only ever answers `handleRequest`.91- **`mdk-contract.json` is the single source of truth** for a worker's92 telemetry, commands, health states and error codes. Validate it against93 `references/mdk-contract.schema.json` (the Kernel terminates workers whose94 capability payload is malformed, and rejects commands not declared in it).95- **Never add transport-level envelope fields.** The envelope is exactly96 `{ id, version, type, action, sender, target, deviceId, timestamp, payload }`97 — extend `payload` instead.98- **Use canonical `@tetherto/mdk-*` names only** — the full list lives in99 [`references/package-index.md`](./references/package-index.md).100- **Never invent UI prop names or telemetry fields** — registry + contracts101 only (`mdk-ui-component` / `mdk-gateway-plugin`).