# bambulab/ JSON Schemas Documentation/validation schemas for Bambu's raw MQTT wire format, mirroring continuum-proxy's `src/printer/bambu_commands/` — not used for codegen (the Rust structs there are hand-written; see that module's doc comment for why), but genuinely useful on their own: language-agnostic documentation of the wire format, and usable to validate a captured MQTT payload without writing any Rust to do it. ## Layout ``` bambulab/ envelope.schema.json the base — sequence_id + command, shared by every command in every generation, so it lives here unversioned, not duplicated under v1/v2 v1/ request.schema.json BambuRequest dispatcher — {"info": ...} / {"pushing": ...} report.schema.json BambuReport dispatcher request/ get_version.schema.json pushall.schema.json report/ get_version.schema.json pushall.schema.json module_info.schema.json v2/ add the same request/report split once V2's wire format is known to differ from V1's ``` ## The "inheritance" pattern Every command/response schema *extends* `envelope.schema.json` with `allOf` + `$ref`: ```json { "allOf": [ { "$ref": "../../envelope.schema.json" }, { "type": "object", "properties": { "command": { "const": "get_version" } } } ] } ``` This is genuinely closer to real inheritance than anything else in this project's schema stack (proto, Rust): the instance must satisfy the base schema *and* the extension schema simultaneously, and — verified with negative test cases, not just asserted — `envelope.schema.json`'s `required: ["sequence_id", "command"]` is actually enforced on every schema that extends it, not just copy-pasted as documentation. Proto and Rust only ever gave us composition (embed a field holding the base), never something that reuses a *named, referenced* schema's constraints automatically like this. **One gotcha if you add a new base-style schema**: don't set `"additionalProperties": false` on something meant to be `allOf`-extended. `allOf` validates every sub-schema against the *whole* instance independently — it doesn't merge object schemas — so a closed base schema would reject every field the extending schema adds. Leave `additionalProperties` unset (defaults to allowed) on anything used as a base; enforce closedness only on the top-level dispatcher schemas (`v1/request.schema.json`/`v1/report.schema.json` do this correctly — check their `additionalProperties: false`). ## Validating something `$ref` resolution here relies on each schema's `$id` as the base URI for its own relative refs (standard JSON Schema behavior) — register schemas by `$id`, not by filename, or you'll hit collisions (`get_version.schema.json` exists in both `request/` and `report/`): ```python from referencing import Registry, Resource from jsonschema import Draft202012Validator import json, glob resources = [ (json.load(open(p))["$id"], Resource.from_contents(json.load(open(p)))) for p in glob.glob("**/*.schema.json", recursive=True) ] registry = Registry().with_resources(resources) schema = json.load(open("v1/request.schema.json")) Draft202012Validator(schema, registry=registry).validate( {"info": {"sequence_id": "0", "command": "get_version"}} ) ```