Protocol versions
The loopback wire protocol between the game plugin and the sidecar is a versioned compatibility contract, not a build dependency. Nothing compiles the three sides together, so the number is what stops a mismatch from being discovered as corrupted data.
The current protocol is 7.
Three declaration sites
Section titled “Three declaration sites”The same number is written down in three places, and they must move together.
| Where | What declares it |
|---|---|
link/sidecar/src/main.rs |
PROTOCOL_VERSION, currently 7 — what the sidecar speaks |
servuo-plugins/overlay.toml |
protocol, currently 7 — what the plugin overlay speaks |
| The bundle manifest | Copied from overlay.toml by CI, so a released pair carries its own claim |
How a mismatch is caught
Section titled “How a mismatch is caught”Two independent mechanisms, at two different boundaries.
Sidecar ↔ website. Every sidecar response carries X-UOLink-Version. A mismatch is
rejected with 409 rather than mis-parsed. The website’s protocol expectation is
admin-managed, alongside the base URL and token, on the shard configuration screen.
Overlay ↔ sidecar. The installer resolves a bundle — an exact, protocol-checked sidecar and overlay pair published by CI — and never “latest of each”. That is the whole reason bundles exist: two independently released components that must agree cannot be allowed to be chosen independently.
What a bump obliges
Section titled “What a bump obliges”Changing a message shape means editing every side plus the specification. The most recent bump touched five repositories:
| Repository | What had to change |
|---|---|
servuo-plugins |
The handlers, the caps and switches in Bridge.cfg, and overlay.toml |
link |
PROTOCOL_VERSION, and the endpoints that carry the new commands |
module-uo |
The verbs it declares, their option sources, and the ingest |
website |
Core learned a shape it had not had — a lease aimed at one named target |
docs |
The protocol document and the integration guide |
The website row is the one worth noticing. Core holds no game connection and names no
game noun, so most protocol bumps do not reach it at all — the two before this one did not.
This one did, because what changed was not a game noun but the shape of a thing core owns
the ledger for.
A protocol bump can also require a store migration, because the sidecar persists what it forwards. That is not automatic, and it has happened once: version 4 added a column to a table that already existed. Versions 5, 6 and 7 needed none, because every frame is persisted whole — a bump that only widens a frame, or adds a kind, or adds a guarantee about how a command is executed, asks nothing of a store that defines no schema for a frame’s contents. That is the dumb-forwarder property paying for itself.
This is not the module API version
Section titled “This is not the module API version”Two different numbers, versioning two different contracts, and confusing them is easy.
| Versions | Lives in | Checked | |
|---|---|---|---|
PROTOCOL_VERSION |
The game ↔ sidecar wire | link, servuo-plugins, the bundle |
X-UOLink-Version, and the installer’s pairing check |
MODULE_API_VERSION |
The website ↔ module contract | website, and every module’s coreApi |
At module load, before the module’s code runs |
A module that never talks to a game server has no protocol version at all. See The module manifest.
When a contract owes a bump
Section titled “When a contract owes a bump”The rule this project settled on: a contract owes a bump only once it has landed on
main.
While a version has only ever existed on a development branch, additions join it in place rather than forcing a new number. Once it has shipped, it is somebody else’s dependency and a change to it is a change to a published contract.
If you are building a bridge for another game
Section titled “If you are building a bridge for another game”You do not inherit this protocol — you define your own between your plugin and your sidecar. What is worth inheriting is the shape:
- Declare the version on both sides, in files a release can read.
- Make a released pair carry its own compatibility claim, so a deployment tool can refuse a bad combination rather than discovering it at runtime.
- Reject a mismatch loudly and early. A
409is a good outcome; a successful parse of a message you did not expect is not.
Canonical documents
Section titled “Canonical documents”link/v7.md
is the current protocol’s record, including its cross-repository obligations, and
link/v6.md
the one before it;
link/PLAN.md
§7 is the wire protocol, and
link/INTEGRATION.md
the integration guide.