0.13.1 Build on MDK
Seoul Hackathon Nov 2026, on MDK 0.13.1
Tested against v0.13.1 on 4 November 2026. The mdk run path runs the 0.13.1 packages. The example
site and the example apps install from GitHub main, not from a release, and on that date they ran 0.13.0.
What is MDK?
MDK, the Mining Development Kit, is an open source framework that lets your code read and control any kind of device or service. The same building blocks serve a home miner on a shelf and a site with thousands of machines.
Every miner turns electricity into hashrate and heat. At home, that makes it a heater that earns bitcoin; at scale, it makes a site one of the most flexible loads on the grid. MDK is the data and control layer that lets software and AI agents see those machines and steer them.
You build on two pieces:
- Workers connect a device or service to MDK: a miner's firmware, a power meter, a cooling system, or an API such as a power-price feed. A Worker is a declarative contract filled in from the device's spec, designed so a coding agent can write one.
- Apps are standalone projects on top. They read live data and send commands through MDK, and several apps can run against the same site.
Where your code plugs in · 4 layers
Data flows up through MDK to your app, and commands flow back down. Write a Worker when MDK can't reach a device yet, and an app when it already can.
See Architecture.
You don't have to start from zero: there's already a set of Workers built by the industry that you can use. Every Worker comes with mock data, so you can test against it without hardware.
The MDK CLI is the entry point for both. MDK is open source under Apache 2.0 and vendor-neutral, and it runs on your own infrastructure.
Mining comes first, but the goal is bigger: a standard for how intelligent systems work with the physical world, from mining sites to data centers and robotics. What you build at this hackathon is an early piece of it.
Challenges and prizes
MDK has two challenges at this hackathon, each with one winner who takes home a Heatbit Bitair, an air purifier with a built-in solo Bitcoin miner, courtesy of Heatbit.
For both, you can build an MDK app, a new Worker for a device or service MDK doesn't support yet, or both. No hardware is needed: you can build against MDK's mock environment. The ideas below are starting points, not a checklist.
Hashrate at home
A home miner is a heater that earns bitcoin. This prize goes to the best project built on MDK that makes mining useful at home: it heats what needs heating, reacts to what's happening in the house, and runs without supervision.
Ideas
- Heat a pool, hot tub, water tank or greenhouse, mining only as hard as the heat is needed
- A comfort controller that runs miners based on room temperature, air quality, and quiet hours
- Mine on solar surplus or off-peak power, and back off when electricity gets expensive
- Show the real cost of heat: sats earned versus a regular electric heater
What judges look for
- Real problem: would someone mining at home install it and keep using it?
- It works: a live demo on real hardware or the mock environment beats slides
- Built on MDK: telemetry and control go through MDK, not around it
- Everyday UX: a non-technical household can set it up and understand it
- Safe by default: respects device limits and fails safe if a sensor or the network drops
- Bonus: open source and documented, so others can build on it
Hashrate at scale
A mining site is one of the most flexible large loads on the grid: it can shed power within seconds and bring it back on demand. This prize goes to the best project built on MDK that turns that flexibility, and the data behind it, into value for operators, energy producers, or the grid. Workers can wrap APIs too, such as a power-price feed or a grid signal.
Ideas
- Curtailment: throttle or power down automatically on price spikes, grid alerts or a site power cap, then ramp back safely
- Demand response: answer grid signals fast enough to sell flexibility, and prove the megawatts delivered
- Profit-aware control: set each machine's power target from hashprice, energy cost, and its own efficiency
- Follow the output of a solar or wind farm, or a flare-gas site
- Site health: catch failing machines, hot spots or cooling problems early, or build an AI agent that proposes fixes for an operator to approve
What judges look for
- Realism: would an operator trust it with a real fleet, and does it match how sites and energy markets work?
- Safety: gradual ramps, hardware and contract limits respected, sensible behavior when data or connectivity is missing, a manual override
- Measurable impact: show the numbers (cost saved, MW curtailed, response time, revenue) on real or simulated data
- Built on MDK: telemetry and control go through MDK, not around it
- Scale and demo: works from one rack to thousands of machines, and the demo actually runs
How to
Prerequisites
Both paths below need:
Cloning the example site also needs:
- PM2 (
npm install -g pm2) - Outbound UDP to the public HyperDHT bootstrap nodes. The example site has no private DHT setting. If the venue network blocks outbound UDP, use the
mdk runpath, which runs its own DHT bootstrap on your machine
See also Run a mining site end to end and Run the CLI with npm.
You can build with MDK in these ways, and mix them:
- Run a site: put existing workers and apps together into a running site.
- Write a worker or an app for your own site.
- Publish a worker or an app for any site to install.
For both challenges, the usual entry is: start from a site that runs on mocks, then add a worker for the signal you need (a temperature, a price, a grid event). Finally, write an app that reads the data and sets miner power.
The example site, mdk-app-example-site, does all of this. It runs three miner brands, four pools, a power meter, and five apps against mock devices. See its README, section "Dependencies and how they are integrated".
See Run a mining site end to end tutorial for more.
MDK npm packages
(all 0.13.1, scope @tetherto)
| Package | What it gives you |
|---|---|
mdk-cli | The mdk command, which runs and checks a stack: onboard (writes mdk.yaml), create worker, create app, create dashboard, add worker and add app (from npm or GitHub), validate, run, status, skill add, plus the access commands rbac init | apply | show, user add | passwd | disable | enable | remove | list, serviceaccount, login, logout, whoami |
mdk-skill | Agent skills (SKILL.md) for coding agents such as Claude Code or Cursor. Install them with mdk skill add |
mdk-kernel | The Kernel: device and worker registry, access policy, command routing |
mdk-core | Bootstrap helpers for the Kernel and Gateway, local discovery, and services for workers (logs, alerts, stats, settings) |
mdk-worker | The worker runtime (WorkerRuntimeV2). It hosts a worker plugin's devices and connects them to the Kernel |
mdk-gateway | The HTTP gateway. It serves app routes (/apps/<name>/…) and the UI |
mdk-app-runtime | Runs one app's controllers in its own process |
mdk-client | Client that calls the Kernel over HRPC |
mdk-identity, mdk-rbac | Users, service accounts and tokens, and role-based access checks at the Gateway, MCP server and Kernel |
mdk-mcp | MCP server that exposes app routes as tools for AI agents |
mdk-ui-foundation | Headless UI state (Zustand stores, TanStack Query client) |
mdk-react-adapter | React bindings, and the host side of app UI modules (MdkAppProvider, checkAppUiModule) |
mdk-react-devkit | React UI primitives and mining components: charts, tables, header stats, sidebar |
mdk-ui-agent | Co-pilot chat panel for the agent app |
Packages is the maintained list, grouped as Core, Extensions, UI and Tools, with what each package is for and how to install it.
To check which workers already exist, see Supported Workers, generated from each Worker's contract so it cannot drift from what ships.
The example apps are on GitHub only, not on npm. Install them from GitHub (mdk add app github:tetherto/<repo>, or a git+https://… dependency):
- mdk-app-operation-center: site dashboard, explorer, containers, power commands
- mdk-app-reporting-tool: hashrate, power, efficiency, cost and pool reports
- mdk-app-demo: aggregated live and historical telemetry
- mdk-app-agent: AI agent chat sessions with operator approvals
Supported apps lists the apps with the routes each one serves.
Start here: Hashrate at home
Starting site. A home setup is usually one miner, a meter or smart plug, and one or two sensors. You can get there in two ways:
mdk onboardwith one miner worker on a mock. For example,mdk add worker sealminer/sealminer-mdk-workeradds one SealMiner withconfig.mock: true.mdk runcan only mock a worker that shipsmock/server.js. Among the miner workers that's SealMiner only. The Whatsminer and Antminer mocks run only in the example site, which starts them itself.- Trim the example site. Keep one miner in
config/devices.json, and delete the roles you don't need frompm2.roles(the other miner brands, the pools you don't use,app-demo).
What already exists:
- Miner power control: the commands are listed under "Read data and control miners" below.
- Electricity use: the miner's
powertelemetry, or a site meter (the SATEC power meter worker). - Earnings: the OCEAN pool worker's
estimated_earningsandbalance.
What you'll likely write. Write a worker for each home signal: room or water temperature, air quality, solar output, electricity tariff, quiet hours. Each is usually small. Start from one of these:
- A sensor or plug on your LAN: copy a miner worker's structure, and keep only its
telemetryand the one or two commands you need. - A web API, such as a tariff or a solar forecast: use
ocean-mdk-workeras the model. It wraps a pool's HTTP API and reportstelemetryonly, with no commands. Give it amock/that replays a realistic day: a cold morning, a price spike, a sunny afternoon.
The app. A control loop that runs on its own:
- Read the room temperature (or tariff, or solar surplus).
- Pick a power mode or power percentage for the miner.
- Send it.
- Check the result on the next telemetry poll.
Run the loop from the app's main (see mdk-app-operation-center/plugin/main.js for a background sampler). Give it a small UI page so a household can set a target temperature and quiet hours, and see what the miner is doing and why.
The "real cost of heat" comparison. Mining heat versus an electric heater is a calculation over data MDK already has:
- Electricity used: energy in kWh from the miner's
power(or the meter) × your tariff. - Earnings: sats from the pool worker's
estimated_earnings, or from the hashrate and network difficulty.formatBitcoinin@tetherto/mdk-react-devkitrenders an amount in eitherBTCorsatsfor the UI. - The comparison: an electric heater turns the same kWh into the same heat, with no sats. The
/api/reporting/financialsand/api/reporting/costsroutes in the Reporting Tool show one way to structure these numbers.
Start here: Hashrate at scale
Starting site. Use the example site as it is. It has 10 miners in 3 containers, a site power meter, pools, the Operation Center and the Reporting Tool. To show scale, add more mock miners to config/devices.json. Each entry gets its own mock, so the only limit is your machine. Add them to the Operation Center's layout too, so they show up in containers.
Benchmark results and operating limits has measured envelopes if you need to show how the shape scales past your laptop.
What already exists:
- Commands across many miners: the Operation Center sends power commands to many miners at once (
POST /apps/op-center/api/commands/power-modeand/power-pct), a few at a time (config.commands.concurrency). By default it answers once the commands are accepted, without waiting for them to finish. Setconfig.commands.verify: trueto have it wait for each one. Readplugin/lib/commands.jsbefore writing your own. - Measured site power: SATEC meter readings at
GET /apps/op-center/api/power-meters, the history at/api/history, and the Reporting Tool's/api/reporting/consumption. Use these to prove the megawatts curtailed and the response time. - Efficiency per miner: the
efficiencyandhashrate_idealtelemetry, plus the Reporting Tool's hardware catalogue (config/reporting/hardware-catalogue.json) with nominal TH/s and watts per model. These let you rank which machines to turn down first. - AI agent with operator approval: the agent app (
@tetherto/mdk-app-agent) runs chat sessions that ask an operator to approve an action before it runs.@tetherto/mdk-ui-agentgives you the chat panel. Themcprole exposes every app's routes as tools, and Connect an AI agent over MCP walks through giving one its own service account. Routes marked"safety": "write"stay hidden unless writes are allowed, so an agent can read freely but can't act on its own.
What you'll likely write:
- A worker for each market signal: energy price (day-ahead or real-time), a grid frequency or demand-response event, a site power cap, or the output of a solar or wind farm. Model it on
ocean-mdk-worker(an API wrapped as telemetry), and give it a mock that can trigger a price spike or a grid event when you ask for one in a demo. - A controller app: it reads those signals and the per-miner efficiency, then sets power targets.
- Give it a dashboard page with the current target, what the site actually draws, and an event log.
- Add a report that adds up MW curtailed, response time, and cost saved or revenue earned.
Read data and control miners
Apps talk to the Kernel through the client the app runtime hands them (require('@tetherto/mdk-gateway/plugin').config.mdkClient). The calls the example apps use are:
| Call | Use |
|---|---|
listWorkers() | Find the workers and their devices |
getCapabilities(deviceId) | Which telemetry and commands a device supports |
pullTelemetry(deviceId, …) | Latest values: hashrate_rt, power, efficiency, temperature, power_mode, status, … |
sendCommand(deviceId, command, params) | Queue a command. It returns { commandId, status: 'QUEUED' } |
getCommandStatus(commandId) | Did it succeed, fail or time out |
Gateway apps shows these calls inside a working route handler, and Protocol messages has the envelope they travel in.
Power commands differ by brand. Check getCapabilities before sending one:
| Worker | Power commands |
|---|---|
whatsminer-mdk-worker | setPowerMode { mode: low | normal | high | sleep }, setPowerPct { pct: 0–200 } |
antminer-mdk-worker | setPowerMode { mode: low | normal | high | sleep }, setHashratePercent { pct } |
sealminer-mdk-worker | setPowerMode { mode: low_power | normal | high_performance | sleep }, setPowerLimit { watts: 2000–20000 }, suspend, resume |
sleep and suspend stop the miner. Use them for a full shutdown, and make sure your app can bring miners back. The app needs devices: write in its mdk-app.yaml permissions to send commands, and devices: read plus workers: list to read telemetry.
Each Worker's guide carries its own commands and their bounds: Whatsminer, Antminer, Avalon.
Safety (both challenges)
Judges weigh safety heavily. Build these in from the start:
- Ramp gradually. Step
setPowerPctorsetPowerLimitover seconds or minutes, and stagger miners. Never switch a whole site at once. - Respect limits. Clamp every target to the ranges the worker's contract declares, the site or contract power cap, and the household's comfort settings. Validate before you send.
- Fail safe. When a sensor, price feed or the network goes silent, fall back to a defined state: hold the current setting, or drop to a safe low mode. Don't keep acting on stale data. Watch telemetry timestamps and the miner
status. - Check that it worked. Follow every command with
getCommandStatusand the next telemetry value. Retry or alert on failure. - Manual override. Give operators a switch that pauses automation, and show when the automation is in control. The Operation Center's
commandsEnabledflag is one example of turning writes off. - Least access. Request only the
permissionsyour app needs. Keep write routes marked"safety": "write"so that MCP agents need explicit permission to use them. - Demo the failures. Kill the price mock or the sensor mock live and show what your app does.
Write actions covers the approval flow, and Security boundaries covers what the Kernel enforces whatever your app does.
1. Build a site from existing workers and apps
The quickest start is the mdk CLI:
npm i -g @tetherto/mdk-cli@0.13.1Or run it without installing anything, which suits a first try or a CI step:
npx @tetherto/mdk-cli@0.13.1 <command>mkdir mdk-site-demo && cd mdk-site-demo
mdk onboard
# interactive: writes mdk.yaml and package.json, can add dashboard and MDK skillmdk add worker sealminer/sealminer-mdk-worker
# a miner with a bundled mock (mock: true)mdk add app github:tetherto/mdk-app-operation-centermdk run
# starts the Kernel, workers, apps and Gateway (Ctrl+C stops)# open second terminal
cd mdk-site-demo
mdk status# add new user
cd mdk-site-demo
mdk user add {username} --admin# to run UI
cd mdk-site-demo
mdk run dashboard
# UI link - http://localhost:3030/
# or: cd apps/dashboard && npm run devThe operator co-pilot panel appears in the dashboard when the agent app is installed and you start the UI with mdk run dashboard. Starting the UI with plain npm run dev leaves it out, unless you build it with VITE_AGENT_COPILOT=true and its Gateway serves /agent/*.
Notes from a test run
npm i -gcan fail withEACCESwhen the global npm prefix belongs to root, as in a default Linux Node install. Use thenpxform, or install Node with a version manager such as nvm.mdk onboardneeds a real terminal. It fails when piped or run from a script, with "mdk onboard needs an interactive terminal (TTY)".mdk user addprompts for the password, then asks for it again to confirm.github:installs take the repo'smainbranch, not a release. On 4 November 2026,mdk add app github:tetherto/mdk-app-operation-centerinstalled the Operation Center 0.13.0.mdk statusshows the version of each app.- Ports: the Gateway listens on 3847, the Kernel on 3848, and the private DHT bootstrap on UDP 49737. If another stack already uses one of them,
mdk runstops with "port … is already in use" or "address already in use". Changespec.gateway.port,spec.kernel.portorspec.network.dht.portinmdk.yaml. - App routes mount under the app's name.
mdk add app github:tetherto/mdk-app-operation-centerserves the Operation Center at/apps/operation-center/…. The example site names the same appop-center, so its routes in this guide read/apps/op-center/…. - The example apps aren't on npm, so
mdk add app @tetherto/mdk-app-…fails with a 404. Use thegithub:form above. - Workers without a
mock/server.js(Whatsminer, Antminer) are added without a mock, and their deviceoptsare empty.mdk addsays so. Fill them in for real hardware. The Antminer worker lives atgithub:bitmain-official/antminer-mdk-worker. - Sign-in: the Gateway made by
mdk runrequires sign-in, so app routes answer 401 to anonymous requests.mdk onboardwrites a starterspec.rbac, andmdk rbac initadds one to a spec without it.mdk user addcreates the first operator, andmdk runrefuses to boot a Kernel that no one could administer. See Create the first operator,mdk userandmdk login. - The Operation Center shows only the devices its
layoutnames. Added withmdk add app, itslayoutis empty, so it reports no miners and 0 W while the SealMiner mock runs. Place each device underconfig.layout.containersin itsspec.appsentry, as the app's README shows. - The agent app needs a model. With it installed, the co-pilot panel appears, but every session answers 503
config.agent missinguntil itsspec.appsentry setsconfig.agent.provider: a local model server (kind: qvac) or a hostedopenai-compatibleendpoint with anapiKey. - The example site's Operation Center lists no power meters. Its
layoutsetsmeterDeviceId: nullon every container, so/apps/op-center/api/power-metersreturnsmeters: []. The SATEC readings are in the Reporting Tool's/api/reporting/consumption.
CLI reference has every command, flag and default, grouped as
mdk --helpgroups them. Run the CLI with npm covers the install on its own, and Build a minimal single-page dashboard coversmdk run dashboard.
You can also clone mdk-app-example-site and edit it. It wires the same packages by hand under PM2 instead of mdk run:
- Kernel and Gateway:
config/site.deploy.jsonsets the ports and the data directory (.site-data/). It also lists the processes to start underpm2.roles. - Devices:
config/devices.jsonlists the miners and meters. Each worker has a matching mock, so no hardware is needed. - Apps: listed in
gateway.pluginDirs. - Version: a clone of
main, not a release. Itspackage.jsonsets the@tetherto/mdk-*versions; on 4 November 2026 that was 0.13.0. - Run it:
npm run setup, thennpm start. The site is athttp://localhost:3000. On a slow machinenpm startcan report "Site did not respond within 60s" before the Gateway is up. Checkpm2 listand try the URL again.
2. How vendor workers are integrated
Vendor workers are worker plugins published in the vendor's own GitHub repo.
Examples are whatsminer-mdk-worker, antminer-mdk-worker, sealminer-mdk-worker, ocean-mdk-worker, emcd-mdk-worker, spiderpool-mdk-worker and foundry-mdk-worker.
Each one is a package with these parts:
mdk-contract.json: what the device reports and which commands it takes;- handlers that talk to the device;
- a
mock/server that pretends to be the device.
Workers describes the contract and the runtime every one of these packages implements.
In the example site :
- The worker is a Git dependency in
package.json, pinned to a commit:"whatsminer-mdk-worker": "git+https://github.com/whatsminer/whatsminer-mdk-worker.git#<sha>". - An adapter in
backend/adapters/(for examplewhatsminer-adapter.js) hosts the plugin onWorkerRuntimeV2from@tetherto/mdk-worker. It turns the devices inconfig/devices.jsoninto the runtime's device list. backend/site.jsstarts the worker and registers it with the Kernel. It also starts the vendor's mock on a local port, with one mock device per configured device.deploy/run-process.jsgives each worker its own PM2 roles, such asworker-antminerandmocks-antminer.
With mdk run, steps 2 to 4 aren't needed: mdk add worker <npm name | github:owner/repo> installs the worker and adds it to spec.workers. If the worker ships mock/server.js, mdk add sets config.mock: true and mdk run starts one mock per device. Otherwise you fill in the device opts for real hardware.
3. How workers from the MDK repo are integrated
Some workers still live inside the MDK monorepo (tetherto/mdk, under backend/workers/…), for example the SATEC PM180 power meter. They aren't published to npm, and they require files elsewhere in the monorepo (backend/core, backend/workers/mock). npm can't install a single subfolder of a Git repo either.
So the example site vendors them instead:
npm run setup:satec(deploy/fetch-satec.js) downloads the MDK release tarball that matches the installed@tetherto/mdk-coreversion.- It extracts the worker and the paths it needs into
vendor/mdk-satec/(gitignored) and runsnpm installthere. backend/site.jsthen loads the worker'sstartSatecWorkerand its mock from that folder and starts them, like the other workers (PM2 rolesworker-satecandmocks-satec).
You can follow the same pattern for any other worker in the MDK repo.
Run a multi-process site runs Kernel, Gateway and several Workers as separate supervised processes, the shape the example site uses.
4. How apps are integrated
An app is a package with:
mdk-app.yaml: its id, version, the Kernelpermissionsit needs, an optional backgroundmain, and defaultconfig;plugin/mdk-plugin.json: its HTTP route table, with the controllers that handle each route;- optionally, a UI module in
ui/built withdefineMdkApp(routes, nav sections, panels).
In the example site:
- Install it. The app is a dependency in
package.json, from npm, Git or afile:path. For example:"@tetherto/mdk-app-operation-center": "git+https://github.com/tetherto/mdk-app-operation-center.git", which has no ref, so it followsmain. - Configure it. Add a
gateway.pluginDirsentry:{ "name": "op-center", "package": "@tetherto/mdk-app-operation-center", "config": { … } }. Then addapp-op-centertopm2.roles. - Run it. Each app runs in its own
@tetherto/mdk-app-runtimeprocess. It signs in to the Kernel asapp:<name>, which@tetherto/mdk-rbacgrants exactly thepermissionslisted in itsmdk-app.yaml. Its routes are served at/apps/<name>/…. - Show its UI.
ui/src/installedApps.tsximports the app'sui/index.jsandui/style.css, then validates the module withcheckAppUiModule. It mounts the app's pages at#/app/<name>/…insideMdkAppProvider, which sends the app's API calls to/apps/<name>. The app's routes also become a group in the left nav.ui/vite.config.tsdedupes React and the@tethertoUI packages, so the apps share the host's copies.
With mdk run, steps 2 and 3 are done by mdk add app <npm package | github:owner/repo>. It adds the app under spec.apps and writes its service account and its role in spec.rbac. mdk create dashboard scaffolds a UI shell that loads app UIs.
Gateway apps covers
mdk-app.yaml, the route table and the UI module, and What's an app covers why each one runs in its own process.
5. Add your own worker or app to a site
A worker is for a device or API that MDK can't reach yet: a heater, a smart plug, a thermostat, a power-price feed, a grid signal.
- Scaffold it with
mdk create worker <name>in the project. It writesworkers/<name>/withmdk-contract.json,src/,mock/server.jsand a smoke test, and registers the worker inmdk.yamlwithmock: true. Without anmdk.yamlit still scaffolds the worker and prints the entry to add. Or ask a coding agent with the MDK skill installed (mdk skill add --client claude|cursor|all). - Fill in
mdk-contract.jsonfrom the device's spec, write the handlers, and add amock/server.js. The mock is what you'll demo with, so make it easy to trigger the interesting cases. The scaffold stamps the contract withcontractVersion, so MDK checks your units and numeric bounds strictly, which catches a bad range before a judge finds it. - Add it to the site:
mdk runsites:mdk create workeralready listed it underspec.workers(package: ./workers/<name>).- The example site: add it as a
file:dependency, then add an adapter (copybackend/adapters/sealminer-adapter.js), aboot…Workerfunction inbackend/site.js, the mock and worker roles indeploy/run-process.js, and its devices inconfig/devices.json.
An app reads telemetry and sends commands: a curtailment controller, a heat scheduler, an efficiency report.
- Scaffold it with
mdk create app <name>. It writesapps/<name>/withmdk-app.yaml,plugin/(route table and controllers), and a UI inui-src/, built toui/withnpm run build:ui. It also registers the app and its access role inmdk.yaml. - Declare its routes in
plugin/mdk-plugin.json, marking each one"safety": "read-only"or"write". Declare its Kernelpermissionsinmdk-app.yaml, requesting only the access it needs. - Put any control loop in the app's
main. - Optionally, add a
ui/module made withdefineMdkAppand@tetherto/mdk-react-devkit. - Add it to the site:
mdk runsites:mdk create appalready added it underspec.apps(package: <name>), with afile:./apps/<name>dependency inpackage.json.- The example site: add a
gateway.pluginDirsentry with"dir": "../my-app"(or afile:dependency and"package"), addapp-<name>topm2.roles, and add its UI toINSTALLED_APPSinui/src/installedApps.tsxif it has one.
- Check it with
mdk validate app <name>.
Build a third-party Worker and Build your first app with a UI are the long forms of these two paths, Run your Worker covers starting it from the CLI, and Test a Worker covers proving it works before you demo it.
6. Publish a worker or app for others
A worker or app doesn't have to live inside a site. Build it as its own repo, so any MDK site can install it. This also earns the judges' "open source and documented" bonus:
- Package name: name it like the existing ones (
<vendor>-mdk-worker,mdk-app-<name>). - Package contents: a worker ships
mdk-contract.json, its handlers andmock/. An app shipsmdk-app.yaml,plugin/and the builtui/. Use thefilesfield inpackage.jsonto choose what gets published. - Dependencies: list
@tetherto/mdk-*aspeerDependencies(or with a compatible range), so the site's copies are used. - Development setup: keep a small
mdk.yamldev stack in the repo (for exampledev/) that runs your package against mocks withmdk run. Runmdk validate app|worker --path . --smoke --strictin CI. - Publishing: publish to npm, or tag a GitHub release. Sites then install it with
mdk add worker|app <package>orgithub:owner/repo#tag, or as a Git dependency as the example site does. - Docs: document the config keys, the permissions it asks for and its safety behavior in the README. Add a mock so others can try it without hardware.
- Listing: open a PR to add a worker to the supported-workers list.
Build a third-party Worker covers packaging, peer dependencies and publishing from your own repo.
Before you demo
- It runs on mocks from a clean clone with one command, and the README says which one.
- It shows numbers: for home, comfort held, and sats versus heater cost; for scale, MW curtailed, response time, and cost saved or revenue earned.
- It shows a failure: a sensor, feed or the network drops, and the system ends up in a safe state.
- It goes through MDK: telemetry comes from
pullTelemetryand control fromsendCommand. It never talks to a miner's own API directly. - It survives the venue Wi-Fi:
spec.network.dhtinmdk.yaml(bootstrap,host,port) keeps the whole stack on your own machine or a local LAN, with no public network.mdk onboardwrites one bound to127.0.0.1. See the private DHT guide.