# Lumi Companion Protocol v1 Status: experimental. The protocol is versioned independently from Lumi core, the server plugin, companion core, and companion transcription plugin. ## Trust boundaries The OBS bridge accepts only same-user named-pipe clients and speaks only the local IPC subset. The companion owns pairing and connects to Lumi over TLS WebSockets. Lumi authenticates a device before accepting a WebSocket upgrade. The bridge never receives a Lumi device credential and never connects to the network. ## Server connection - Endpoint: `wss:///plugins/lumi_transcription/live` - Header: `Authorization: LumiDevice .` - Maximum structured message: 64 KiB. - Maximum binary audio message: 6,464 bytes (64-byte header plus up to 200 ms of PCM). - The client sends `hello` first. Lumi replies with `hello_ack` or closes with an application error. - Protocol v1 supports `pcm_s16le`; codec negotiation is still explicit so Opus can be added later. - Heartbeats use `ping`/`pong`. A new connection is a new session unless `resume_session_id` names a resumable session owned by that device. Structured messages use the envelope in `schemas/envelope.schema.json`. Supported client events are `hello`, `ping`, `source_update`, `obs_state`, `start`, `stop`, and `ack`. Server events are `hello_ack`, `pong`, `status`, `caption`, `metric`, and `error`. ## Binary PCM frame All integers are little-endian. The fixed header is 64 bytes: | Offset | Size | Meaning | | --- | ---: | --- | | 0 | 4 | ASCII `LACP` | | 4 | 1 | protocol version (`1`) | | 5 | 1 | flags: active `0x01`, muted `0x02` | | 6 | 2 | header bytes (`64`) | | 8 | 4 | sequence number | | 12 | 8 | monotonic capture timestamp, microseconds | | 20 | 16 | session UUID bytes | | 36 | 16 | OBS source UUID bytes | | 52 | 4 | sample rate (`16000`) | | 56 | 2 | channels (`1`) | | 58 | 2 | PCM bits (`16`) | | 60 | 4 | payload bytes | The payload is mono signed 16-bit little-endian PCM. Receivers reject malformed sizes and unsupported audio formats. Sequence gaps are reported; out-of-order frames are discarded. Every queue drops obsolete data rather than blocking a capture thread. ## Local OBS IPC Windows transport is a per-user named pipe named `Lumi.Companion.ObsBridge.v1.`. Messages are length-prefixed (32-bit little-endian), capped at 64 KiB for JSON and 6,464 bytes for audio, and begin with a v1 handshake. The bridge accepts only this allowlist: `hello`, `select_sources`, `caption`, `delivery_state`, `shutdown_notice`, and PCM frames. It cannot execute arbitrary commands. Caption events are revision-aware. Consumers retain the greatest revision for each `(session_id, caption_id)` and discard older revisions, including after reconnect. ## Compatibility Protocol v1 requires companion capability `transcription.capture.v1` and server capability `transcription.server.v1`. OBS delivery is separately negotiated as `obs.caption.native.v1`; its absence keeps test-mode simulation available but blocks live delivery.