# Language bindings `src/gen/binding_schema.json` describes handle families, constructors, methods, arguments and operation/query mappings. `build.rs` derives it from `spec/entities.toml`. Its `layouts` section is manually maintained vocabulary; it does not contain everything needed to generate a bincode codec. Generate and test the Python facade from the repository root: ```sh python3 crates/ocs_doc_api/bindings/python/generate.py > /tmp/ocs_doc.py python3 -m unittest discover -s crates/ocs_doc_api/bindings/python ``` The generated `DocApi(transport, active_tab)` expects a caller-supplied `transport.apply(envelope) -> Receipt`. It does not open a plugin connection. An envelope has `version` and a Python tuple `("Op", operation_dict)` or `("Queries", [query_dict])`. Enum payloads use externally tagged dictionaries, for example `{"CreateSolid": {"Sphere": {"centre": [0, 0, 0], "radius": 2}}}`. The bridge converts these objects to the Rust DTOs and bincode 1.3 wire format, sends `DocApiRequest { tab_id, bytes }`, and decodes `Result`. Host plugin API version 6 and document envelope version 1 are required. For Rust plugins compiled against `ocs_doc_api` with the `doc_api_host` feature, use the `doc_api_for_host` helper to build a typed `DocApi` from any `ocs_plugin_api::host::HostApi` that exposes a `PluginRequestSender` (out-of-process / worker-thread hosts): ```rust use ocs_doc_api::doc_api_for_host; use ocs_plugin_api::host::HostApi; fn on_dispatch(host: &mut dyn HostApi) -> Option<()> { let doc_api = doc_api_for_host(host)?; let doc = doc_api.document(host.tab_id()); let cube = doc.solids().create_cuboid([0.0; 3], [10.0; 3]).ok()?; // ... Some(()) } ``` In-process plugins should use `DocApi::in_process(backend, tab_id)` with a concrete `DocApiBackend`; `doc_api_for_host` returns `None` for hosts that do not expose a `PluginRequestSender`. Decode receipt outcomes as `{"NewId": 42}` or `{"NewIds": [42, 43]}` and query results as externally tagged dictionaries such as `{"Volume": 12.5}`. The facade unwraps these into typed handles or values. Layer results use `{"Layers": [...]}` and `{"EntityLayer": "WALLS"}`. Layer properties (`LayerInfo`, `LayerFlags`, `Color`, `LineWeight`) appear as plain dictionaries in operation payloads, e.g. `{"CreateLayer": {"name": "Walls", "flags": {"frozen": false, "locked": false, "frozen_in_new_viewport": false, "off": false}, "color": {"Index": 7}, "line_type": "Continuous", "line_weight": {"Default": null}, "plot_style": "", "is_plottable": true}}`. XDATA and XRECORD payloads appear as nested externally tagged dictionaries (e.g. `{"XData": {"application_name": ..., "values": [...]}}` or `{"XRecord": {"name": ..., "entries": [...]}}`). The bridge must raise an exception for an error response. Transport binding determines the tab; requesting another tab or combining typed handles from different documents raises an error.