**An open protocol for AI-controlled laboratory in…
An open protocol for AI-controlled laboratory instruments. Think "MCP for lab equipment": one universal way for AI agents to discover an instrument's capabilities, command it, stream its measurements, and walk away with cryptographically signed proof of what was done.
** Working title, protocol v0.3 draft. The wire protocol will change before 1.0. Feedback and prior-art corrections are very welcome; see CONTRIBUTING.md .
Self-driving labs need instruments that agents can operate safely and auditably. Today every vendor speaks a different dialect and every integration is bespoke. Labwire's bet is that the missing piece is small and buildable now:
AI-agent-native. Capability discovery modeled on MCP: an instrument describes its commands as JSON Schema, so any agent framework can drive it with zero glue code: the bundled MCP adapter proves it.
Signed results. Every run can produce an ed25519-signed manifest over the exact telemetry recorded: portable, tamper-evident evidence of what instrument did what, verified by one CLI command.
Safety and physical typing in the protocol. Mandatory UCUM units on every quantity, S0-S3 safety classes where irreversible actions take an operator confirmation and hazardous ones take an operator grant an agent cannot mint, bound to the exact parameters, interlocks, cancellation, and typed errors with retryability. All specified, not vendor add-ons.
Things, not only quantities. v0.3 adds resources (typed, readable instrument state, like a liquid handler's deck) and typed references (parameters that name a well or a site, validated against current state, with errors that hand the agent the read that recovers). Designed so that discovery alone leads an agent to the deck, with no prompt coaching; CI enforces the preconditions, and the demo asserts the behaviour.
Runnable by a stranger in 5 minutes. Zero hardware: the reference implementation ships three realistic simulated instruments.
From PyPI (Python 3.12+), no checkout needed:
pip install labwire
That installs the SDK, three simulated instruments, their drivers, and the labwire CLI. Declare an instrument and drive it end to end, straight from a Python file:
import asyncio from labwire . core import ( PROTOCOL_VERSION , CommandContext , IdentityInfo , Instrument , InstrumentServer , LabwireClient , MemoryTransport , command , ) from pydantic import BaseModel , ConfigDict class MassReading ( BaseModel ): model_config = ConfigDict ( extra = "forbid" ) # closed schema: the unit walker demands it mass_g : float class Balance ( Instrument ): """A one-command instrument. Units are mandatory: omit "g" and this refuses to declare.""" identity = IdentityInfo ( manufacturer = "You" , model = "Balance-1" , serial_number = "B-1" , firmware_version = "1.0" ) @ command ( returns_units = { "mass_g" : "g" }) async def measure ( self , ctx : CommandContext ) -> MassReading : """Report the settled mass.""" return MassReading ( mass_g = 12.3456 ) async def main () -> None : server = InstrumentServer ( Balance ()) client_end , server_end = MemoryTransport . pair () server . attach ( server_end ) async with LabwireClient . attach ( client_end ) as client : descriptor = await client . describe () print ( descriptor . identity . model , "speaks Labwire protocol" , PROTOCOL_VERSION ) handle = await client . submit ( "measure" , {}) result = await handle . result ( timeout = 5.0 ) print ( "mass:" , result [ "mass_g" ], "g" ) asyncio . run ( main ())
Telemetry streaming, safety confirmations, and ed25519-signed run bundles are a few lines more; examples/quickstart.py shows them.
From source, for the full demos and examples:
git clone https://github.com/benchwire/labwire.git && cd labwire make setup # uv installs Python 3.12 + everything uv run examples/quickstart.py # 60 s: drive a simulated balance end to end uv run examples/streaming.py # telemetry, cancellation, interlock recovery make demo # closed-loop optimization + signed evidence
make demo runs a full autonomous experiment campaign: a scripted optimizer tunes heater voltage and reagent flow rate across three simulated instruments, converges on the hidden yield optimum, and ends by verifying the winning run's signed bundle:
safety: pump dispense is class S2 (irreversible); running under the operator standing grant run 13 V= 15.0 V -> T= 68.0 degC q= 127 uL/min yield= 87.2% best= 87.2% converged: best yield 87.2% at 15.0 V (68.0 degC), 127 uL/min in 14 experiments signed evidence: demo_runs/d3b15e9f-... labwire verify: OK - authentic
make demo-claude runs the same loop with a real Claude agent planning the experiments through the instruments' tool schemas (needs ANTHROPIC_API_KEY ; degrades gracefully to the scripted optimizer without it).
flowchart LR subgraph agents [Agents] claude[Claude / any MCP client] script[Optimizer / LabwireClient] end adapter["labwire-mcp<br>(MCP adapter)"] subgraph servers [Instrument Servers - labwire-core] psu[PowerSupply driver] pump[SyringePump driver] bal[Balance driver] end subgraph devices [Native wire protocols - labwire-sim] scpi["SimPSU-3005<br>SCPI over TCP"] serial["SimPump-200<br>serial-style lines"] stream["SimBalance-120<br>streaming readings"] end verify["labwire verify<br>(ed25519 + RFC 8785)"] claude -->|MCP tools| adapter adapter -->|JSON-RPC / WebSocket| servers script -->|discover / command / stream| servers psu --> scpi pump --> serial bal --> stream servers -->|signed run bundles| verify
Loading
The protocol is JSON-RPC 2.0 over WebSocket (stdio specified), with an MCP-inspired initialize/capability handshake, a push-first command lifecycle, sequenced telemetry, protocol-level safety interlocks, and normative signed run manifests. The full specification lives at spec/SPEC.md , and every JSON example in it is machine-validated against the implementation in CI.
Package What it is
labwire-core Server + client SDKs, transports, session layer, signing, JCS
labwire-sim Three realistic simulated instruments speaking native wire protocols
labwire-drivers Drivers wrapping those native protocols as Labwire instruments
labwire-mcp MCP adapter: every instrument command becomes an MCP tool
labwire-cli labwire verify <bundle> : authenticate signed run evidence
labwire-ophyd Bridge: serve any ophyd (Bluesky) device as a Labwire instrument
labwire-pylabrobot Bridge: serve a PyLabRobot liquid handler as a Labwire instrument
spec/ The protocol specification (v0.2 draft)
examples/ Quickstart, streaming/recovery, and the closed-loop demo
Wrapping your own device is a class and a decorator:
class MyPump ( Instrument ): identity = IdentityInfo ( manufacturer = "You" , model = "Pump-1" , serial_number = "001" , firmware_version = "1.0" ) flow = channel ( "flow_rate" , unit = "uL/min" ) # UCUM codes are mandatory @ command ( units = { "volume_ul" : "uL" , "rate_ul_min" : "uL/min" }, returns_units = { "dispensed_ul" : "uL" }, safety_class = "S2" , # irreversible: needs confirmation ) async def dispense ( self , ctx : CommandContext , volume_ul : float , rate_ul_min : float ) -> dict [ str , float ]: """Dispense a volume at a controlled flow rate.""" ...
Serve a simulated instrument in one terminal:
uv run examples/serve_pump.py
Then expose it to any MCP client from another:
uv run labwire-mcp ws://127.0.0.1:9520
Every declared command appears as an MCP tool with its schema, units, and identity, so Claude discovers and drives the hardware natively. See examples/mcp-config.json for a Claude-style MCP server entry.
The three instruments are original simulated device models, with realistic latency, noise, drift, failure modes, and safety interlocks. They are not emulations of any real vendor's hardware, and no compatibility with real instruments is claimed. In the closed-loop demo, th…
本条由桃子采集流水线(启发式模式)自动整理,原文见文末信源。