Versioning and deprecation policy
How MDK numbers releases from v1.0, what counts as a breaking change, and how long a deprecated interface keeps working
TL;DR
- From
1.0.0, MDK follows Semantic Versioning 2.0.0: a breaking change to a public interface ships only in a MAJOR release - A deprecated interface keeps working for at least two MINOR releases and at least six months, whichever is longer, and is removed only in a MAJOR release
- The previous MAJOR line receives security fixes for six months after the next MAJOR ships
- Before
1.0.0(every0.y.zrelease today), any release can break a public interface; theBreaking changessection of the changelog lists each one
Overview
This page is the contract between MDK and the people who build on it. It defines which interfaces MDK treats as public, how the version number signals a change to them, and how much notice an integrator gets before a supported interface goes away. An interface this page doesn't list as public carries no compatibility promise in any release.
Version numbers
Every publishable @tetherto/mdk-* package ships at the same version in every release. One number describes the whole stack, so an
integrator upgrades the Kernel, the Gateway, the client, and the UI packages together, and the internal @tetherto/mdk-* dependencies
are pinned to ^<version> of that same release.
From 1.0.0, the version is MAJOR.MINOR.PATCH:
| Part | Increments when a release | Integrator action |
|---|---|---|
MAJOR | Removes or changes a public interface incompatibly, including removing a deprecated interface | Read the release's Breaking changes and migrate |
MINOR | Adds a public interface or capability, or deprecates an existing one, without breaking existing use | Upgrade freely; plan migrations off anything deprecated |
PATCH | Fixes a bug or a security issue without changing a public interface | Upgrade freely |
Pre-release versions (1.0.0-rc.1, 2.0.0-rc.1) carry no compatibility promise between one another. A release candidate or a MAJOR
release ships only when no documentation debt remains, as the release checklist enforces.
Before 1.0
MDK is in initial development until 1.0.0. In a 0.y.z release, any part of the version can carry a breaking change, including a
PATCH. Pin an exact version (0.12.2, not ^0.12.2) and read the changelog's Breaking changes section before each upgrade.
Interfaces deprecated during 0.y.z can be removed in 1.0.0
itself; the deprecation window below starts at 1.0.0.
Public interfaces
The compatibility promise covers these interfaces of the publishable packages that the package reference lists:
| Interface | What's covered |
|---|---|
| Package entry points | Every export reachable from a package's exports or main entry, and its documented arguments and return shape |
| Gateway HTTP API | Documented routes, methods, request fields, response fields, and status codes (Gateway guide) |
| MDK Protocol | The message envelope, the action catalogue, and each action's payload |
| Worker contract | mdk-contract.schema.json for a given contractVersion |
Stack manifest (mdk.yaml) | Fields under a given apiVersion (mdk/v1) |
App manifest (mdk-app.yaml) | The manifest fields and the route table (mdk-plugin.json) |
mdk CLI | Command names, flags, exit codes, and documented --json output (CLI README) |
| MCP server | Tool names, input schemas, and safety annotations (MCP README) |
| UI toolkit | Exported components, hooks, and stores, with the props and types in dist/registry.json |
| Error codes | Documented error codes; the message text is not covered |
| Environment variables and config | Documented variable names, config keys, and their defaults |
| Runtime baseline | The supported Node.js and npm range in the environment requirements |
These carry no compatibility promise, in any release:
- Packages marked
workspacein the package reference, and every file underexamples/ - Deep imports into a package's internals (
@tetherto/mdk-kernel/lib/...) that itsexportsdoesn't expose - Log lines, error message text, and the on-disk layout of stores, which change without notice; migrations for stored data ship with the release that needs them
- Mock servers and test utilities
- Partner-maintained Workers listed in
external-workers.json, which version independently; their compatibility with MDK is expressed throughcontractVersion - Anything a page marks as experimental
Schema versions
Three interfaces carry their own version identifier alongside the package version:
| Identifier | Where | Changes when |
|---|---|---|
version in the envelope | Every MDK Protocol message | The envelope or an action payload changes incompatibly |
contractVersion | mdk-contract.json | The Worker contract schema changes incompatibly |
apiVersion | mdk.yaml | The stack manifest changes incompatibly |
A new generation of any of these ships only in a MAJOR release. The previous generation stays accepted, alongside the new one, for
the full deprecation window, so a Worker built against contractVersion: "1" keeps loading on the MAJOR release that introduces "2".
Soft freeze
The areas in this table can change in a 1.x release, as long as the change keeps every public interface
compatible. Each change still follows the version rules on this page: an addition ships in a MINOR release, a fix in a PATCH.
| Area | What may change | Guardrail |
|---|---|---|
| Apps MDK ships | Controllers, caching, and aggregation in the apps MDK ships (agent, demo) | Keep each route table (mdk-plugin.json) and the required fields of mdk-app.yaml |
| New apps | New apps and routes, scaffolded by mdk create app or installed by mdk add app | Each app runs in its own @tetherto/mdk-app-runtime process; the Gateway runs no app code |
| First-party Workers | New models, handler internals, and vendor protocol fixes for Avalon, Antspace, Bitdeer, ABB, SATEC, Schneider, Seneca, and F2Pool | Must still validate against mdk-contract.schema.json |
| New Workers | Additional device families and providers | Same contract; the Kernel doesn't change |
| UI toolkit | Components, hooks, and stores in @tetherto/mdk-ui-foundation, @tetherto/mdk-react-adapter, @tetherto/mdk-react-devkit, and @tetherto/mdk-ui-agent, plus the catalog app | The browser still talks HTTP to the Gateway only |
| Operator agent | The charter, tools, session store implementations, and the eval battery of @tetherto/mdk-agent | The agent reaches MDK only through the MCP server, and a session id is not authority |
| MCP tools | Hand-authored tools, and the tools the MCP server derives from an app's mdk-plugin.json | The MCP server stays its own process, binds 127.0.0.1, serves POST /mcp, and exposes only read-only tools by default |
| CLI and skills | mdk commands and @tetherto/mdk-skill | What the CLI generates must pass mdk validate app and the Worker contract |
| Examples and docs | Anything under examples/ and docs/ | Must keep demonstrating the shipping MDK Protocol and manifests |
| Additive schema | Optional fields on mdk-contract.json, mdk-app.yaml, or mdk-plugin.json | A new required field, or a removed one, follows the schema version rules |
Deprecation
How a deprecation is announced
A deprecation ships in a MINOR release and is announced in every place an integrator can meet it:
- The release's changelog lists it under a
Deprecatedsection, with the replacement and the earliest version that may remove it. - The reference docs for the interface mark it deprecated and link the replacement.
- Code carries the marker its ecosystem reads: a
@deprecatedJSDoc tag on exports and UI props,deprecated: trueon a Gateway route or MCP tool description, andnpm deprecatefor a whole package. - Where the interface runs at runtime, it logs a deprecation warning once per process, naming the replacement.
A deprecation always names a working replacement that is available in the same release. MDK doesn't deprecate an interface that has no replacement unless the capability itself is being retired, and then the changelog says so.
How long a deprecated interface stays supported
| Rule | Commitment |
|---|---|
| Minimum window | Two MINOR releases and six months from the release that deprecates it, whichever is longer |
| Removal | Only in a MAJOR release, after the minimum window has passed |
| Behavior while deprecated | Unchanged: a deprecated interface keeps its documented behavior and receives bug and security fixes |
| Schema generations | The previous contractVersion, apiVersion, or envelope version stays accepted for the same window |
A deprecation that misses the cut for one MAJOR release waits for the next; MDK doesn't shorten the window to make a release.
Support for the previous MAJOR line
When a new MAJOR release ships, the previous MAJOR line receives PATCH releases for security fixes for six months. Feature work and non-security bug fixes go only into the current MAJOR line.
Exceptions
A security fix can change a public interface in a MINOR or PATCH release when no compatible fix exists. The changelog lists the change
under Breaking changes and Security, and the security policy covers how the issue is disclosed.
A published version that is broken is deprecated on npm and replaced by a PATCH release, as the release process describes, because npm versions can't be replaced.
Next steps
- Read the changelog: every release's breaking changes, deprecations, and additions
- Check the packages MDK ships: which packages are publishable and covered by this policy
- Confirm the runtime baseline: the Node.js and npm range a release supports
- Follow the release process: how a version is cut, published, and deprecated on npm