Metadata-Version: 2.4
Name: lab-sync-driver-protocol
Version: 0.3.0
Summary: Versioned stdio wire contract between the device engine and out-of-process device drivers
Author: Lab Sync
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Classifier: Typing :: Typed
Requires-Python: >=3.14
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# lab-sync-driver-protocol

The versioned wire contract between device drivers and the supervisor that
launches them. A driver runs as a child process and the two talk
newline-delimited JSON over the child's stdin and stdout: stdout is the
protocol channel and nothing else may write to it, stderr is the driver's log
channel. The package is importable by both sides and depends on nothing, so a
driver speaks the protocol without importing anything of the supervisor's.

Most driver authors want [`lab-sync-driver-sdk`](https://pypi.org/project/lab-sync-driver-sdk/),
which implements the driver side of this protocol from a decorated Python
class. Depend on `lab-sync-driver-protocol` directly only to implement the protocol
yourself, in Python or as a reference for another language.

```bash
pip install lab-sync-driver-protocol
```

## Frames

One JSON object per line. Every request carries an `id`, and every frame a
driver sends in answer carries the same `id` and a `type`:

```text
Request   (supervisor -> driver): {"id": <int>, "method": <str>, "params": {...}}
Reply     (driver -> supervisor): {"id": <int>, "type": "reply", "result": {...}}
Execute stream:                   {"id", "type": "progress", "fraction", "message"}
                           ... -> {"id", "type": "result", "output_json"}
                              or  {"id", "type": "error", "code", "message"}
Telemetry (driver -> supervisor): {"type": "telemetry", "channel": <str>, "payload": {...}}
```

`lab_sync_driver_protocol.wire` holds the framing (`encode`, `decode`, `read_frame`,
`write_frame`), the protocol version (`PROTOCOL_VERSION`, currently `v0`) and
`STREAM_LIMIT`, the line length a reader should accept.

## Methods

The request vocabulary is `handshake`, `describe`, `connect`,
`set_simulation`, `ping`, `execute` (streaming progress/result/error frames),
`abort`, `describe_options`, `estimate_time` and `set_telemetry_demand`.

`describe_options` is optional and additive (the protocol version stays `v0`):
request `{"command": name, "parameters": {…}}`, reply
`{"options": {param_name: [choice, …]}}` — the runtime choices for the
command's `dynamic_options` parameters, best-effort per parameter. A driver
predating it answers with the standard `unknown_method` error frame, which a
supervisor reads as "no dynamic options" rather than a fault.

Telemetry is demand-gated: a driver samples nothing until the supervisor sends
`set_telemetry_demand` with the complete set of channels that should be
running. See the `lab_sync_driver_protocol.wire` module docstring.

## Environment

The supervisor passes per-instance values in the driver process's environment,
since the launch command is shared by every instance of a driver type:

- `STUDIO_DEVICE_CONFIGURATION` (`CONFIGURATION_ENV`): the hardware variant
  the device was added as, one of the `configurations` the driver describes.
- `STUDIO_DEVICE_DATA_DIR` (`DATA_DIR_ENV`): the instance's own writable
  directory, which is also the process's working directory.

## License

MIT
