Skip to content

Development

Local development network

labnet dev runs a complete network on one machine: Central, two Lab PCs, the Control Center web interface and its safe-state watchdog. Everything binds to 127.0.0.1. - The first Lab PC serves two DummyDevices and a simulated optics bench: a laser, an AOM and an EOM. - The second serves a DummyDevice, the SimulatedWavemeter and a two-channel AWG.

Prerequisites: Python 3.11+ and uv. The commands work the same from PowerShell, cmd, or a Unix shell; processes start in the background without opening windows.

uv sync                 # once, and after pulling: .venv with every package, editable
labnet dev up           # seed .devnet/ if needed, start everything, wait until ready
labnet dev status       # health of each process + the device table clients see
labnet dev smoke        # lease every device, call it over gRPC, release
labnet dev down         # stop everything (data in .devnet/ is kept)
labnet dev seed         # start over: a fresh database, users, and settings files

Run them from the repository root with the virtual environment active, or prefix each with uv run. State lives in .devnet/ under the current folder (--dir picks another).

labnet dev status should show:

DEVICE           TYPE                 LAB PC         gRPC TARGET      STATE  LEASABLE
dev01-aom        dummy_aom            lab-pc-dev-01  127.0.0.1:50051  ready  yes
dev01-dummy-a    dummy_device         lab-pc-dev-01  127.0.0.1:50051  ready  yes
dev01-dummy-b    dummy_device         lab-pc-dev-01  127.0.0.1:50051  ready  yes
dev01-eom        dummy_eom            lab-pc-dev-01  127.0.0.1:50051  ready  yes
dev01-laser      dummy_laser          lab-pc-dev-01  127.0.0.1:50051  ready  yes
dev02-awg        dummy_awg            lab-pc-dev-02  127.0.0.1:50052  ready  yes
dev02-dummy-a    dummy_device         lab-pc-dev-02  127.0.0.1:50052  ready  yes
dev02-wavemeter  simulated_wavemeter  lab-pc-dev-02  127.0.0.1:50052  ready  yes

What labnet dev seed creates

Seeding writes central.env, then runs labnet-central-admin setup. That creates the schema and every user, and writes each user's API key into its own settings file:

File in .devnet/ Contents
central.env SQLite database at .devnet/central.db, port 8008
researcher.env Central URL + the researcher key, for clients and the examples
dev-admin.env Central URL + the admin key
lab-pc-dev-01.env ID + key, gRPC :50051, health :9001, inventory labnet_sim.inventories.dev_lab_pc_01
lab-pc-dev-02.env ID + key, gRPC :50052, health :9002, inventory labnet_sim.inventories.dev_lab_pc_02
control-center.env Central URL + the control-center key, port 8080, the experiments and automation folders (experiments/ and automation/ at the repository root, git-ignored, so re-seeding keeps them) and Photo-Agent's folders (papers in literature/)
automation-watchdog.env The watchdog's Central key and port 8081
run/ One pid file per process, so down stops exactly what up started
logs/ One log per process; labnet dev up prints the tail if a start fails

A dev Lab PC file is six lines. Having an API key turns on Central registration and lease checks; having no certificate keeps it on loopback plaintext. .devnet/ is git-ignored, and its keys are throwaway.

To change the topology (more Lab PCs, other ports), edit DevNetwork in labnet/dev/network.py, add an inventory under packages/labnet-sim/src/labnet_sim/inventories/, then run labnet dev down, labnet dev seed, and labnet dev up.

The Control Center

labnet dev up also starts the web interface at http://127.0.0.1:8080/status: every Lab PC, its devices, their state (available, leased, unavailable), and each device's callable methods. The Network tab is that status page, grouped by Lab PC. The Devices tab lists every device in one list. On both, "Device control" opens the device's own page at /<device-id> (e.g. http://127.0.0.1:8080/dev02-wavemeter).

The wavemeter's page has a live graph with Play/Pause, a time window, and CSV export; parameters that are sent when Play is pressed; and a script box. Other device types get a script box until they have their own panel (see Device control pages).

The Experiments tab lists the lab's setup diagrams. View Experiment opens one on a canvas: - Drag devices and passive optics (mirrors, beamsplitters, filters…) onto the canvas, and connect them with beams or signal cables. - Click a device to set each setting to a fixed value or a sweep, and to choose which readings to record. - Export script turns the diagram into a Python script that runs it and writes a CSV.

The Automation tab holds projects an agent will work in. Each project is a folder: - Literature: the shared lab library is already there. - Data: your example data, and the data the agent makes. - Experiment_layout: snapshots of the canvases it uses. - Tasks: one Markdown file per task. - ScriptsUtilized, Protocols and Analysis: where the agent's work goes.

You upload, edit and link experiments from the page. Folders the agent writes are read-only to people. Tasks are queued as runs: the agent plans, and any device control waits for a person to approve a protocol whose bounds the Control Center and the Lab PCs enforce. See Automation. To bring it into use in the lab, follow the Automation go-live checklist.

The Photo-Agent sidebar is Claude Code: ask it about LabNet, attach data or papers, or ask it to set up an experiment. It proposes a diagram you can apply to the canvas. See Experiments and Photo-Agent.

The Control Center is just another LabNet client with its own Central user, so the browser never sees an API key. In both development and the lab it runs on the same computer as Central and reaches it over loopback. Only the settings file's location and the address people open differ:

Development Lab (on central_server_pc)
Settings .devnet/control-center.env (written by labnet dev seed) C:\ProgramData\LabNet\control-center.env
LABNET_SERVER_URL http://127.0.0.1:8008 http://127.0.0.1:8008 (same computer as Central)
Started by labnet dev up you, in its own window (see starting the lab by hand)
Address http://127.0.0.1:8080/status https://lab-control-center/status or https://192.168.50.10:8443/status, via Caddy
Logins none One per person, checked by Caddy (scripts/lab/setup_logins.ps1; see Logins)

Use lab-control-center, with hyphens: underscores are not valid in host names or certificates. Setup is in Control Center.

Using the dev network from your own code

Point clients at the researcher file once, then run any script:

export LABNET_ENV_FILE=.devnet/researcher.env        # PowerShell: $env:LABNET_ENV_FILE = ".devnet\researcher.env"
python examples/01_hello_device.py
python examples/04_scan_two_devices.py               # leases devices on both Lab PCs

examples/README.md describes all five examples.

The change loop: down → update → generate → redeploy

Running processes never reload code. Device objects are built once at startup, so every change follows the same loop:

labnet dev down                      # 1. take the network down
#                                       2. edit protos / physical.py / inventories
labnet driver build --core           # 3. regenerate (core protos; in a driver package, labnet driver build)
pytest                               #    and run the tests
labnet dev up                        # 4. bring it back with the new code
labnet dev smoke                     # 5. prove every device still answers

Skip step 3 when you only changed an inventory or Python code.

When the change touches only one component, restart just that one and leave the rest running:

labnet dev restart control-center    # Control Center Python or its .env
labnet dev restart lab-pc-dev-02     # that Lab PC's inventory or .env
labnet dev restart central           # Central code or central.env

Control Center page files (HTML, CSS, JS) need no restart: refresh the browser.

Adding or removing instruments of an existing family

No code generation is needed. Edit the Lab PC's inventory, for example packages/labnet-sim/src/labnet_sim/inventories/dev_lab_pc_02.py:

def create_devices():
    return [
        PhysicalDummyDevice(device_id="dev02-dummy-a"),
        PhysicalSimulatedWavemeter(device_id="dev02-wavemeter"),
        PhysicalSimulatedWavemeter(device_id="dev02-wavemeter-b", center_nm=852.347),  # new
    ]

Then run labnet dev restart lab-pc-dev-02. Device ids must be unique across all Lab PCs. A removed device stays in Central's table as stopped and not leasable. Run labnet dev seed to clear it, or if you moved a device id to a different Lab PC (Central rejects that as an ownership conflict).

Running the pieces by hand

From the repository root:

uv sync
uv run labnet dev up
export LABNET_ENV_FILE=.devnet/researcher.env      # PowerShell: $env:LABNET_ENV_FILE = ".devnet\researcher.env"
uv run python examples/01_hello_device.py

This runs Central and two simulated Lab PCs on loopback. The equivalent manual steps are:

labnet-central-admin --env-file central.env setup --user researcher --lab-pc lab-pc-dev-01 \
    --write-env . --server-url http://127.0.0.1:8008
labnet-central --env-file central.env                 # terminal 1
labnet-lab-pc --env-file lab-pc-dev-01.env            # terminal 2 (serves one simulated device)
LABNET_ENV_FILE=researcher.env python examples/01_hello_device.py

Here central.env contains a single line such as LABNET_DATABASE_URL=sqlite:///C:/tmp/labnet/central.db.

Tests and checks

From the repository root (uv sync installs every package and the tools):

uv run labnet driver build --core --check --import-check
uv run lint-imports
uv run pytest

The suite covers Central storage, leases, and the admin CLI; client renewal and settings; generated contracts and both device families; device workers; TLS policy and real TLS handshakes with labnet-certs certificates; Lab PC settings rules; and a full Central-to-Lab-PC-to-client stack. It also runs every script in examples/ against real servers.

labnet driver build --core regenerates LabNet's own protos (a driver package runs labnet driver build in its folder). Generated files are pinned to LF line endings in .gitattributes because --check compares bytes.

Repository layout

Path Purpose
packages/ The installable packages: labnet (full guide), labnet-control-center, labnet-automation and labnet-sim
packages/labnet/src/labnet/protos/ LabNet's shared protobuf messages and RPC options
packages/labnet/src/labnet/driver/ labnet driver build and new: contract validator, code generator, driver template
packages/labnet-sim/ The simulated device families: a complete driver package
packages/labnet/src/labnet/lab_pc/ The labnet-lab-pc runtime and its settings rules
packages/labnet-control-center/src/labnet_control_center/ The labnet-control-center web interface (backend + static/ pages)
packages/*/tests/, tests/ Each package's tests; full-stack and example tests
sites/pqt/ A lab's configuration (here the PQT lab's): env templates, the Caddyfile template, and Lab PC inventories
examples/ Experiment scripts 01–05
scripts/lab/ setup_logins.ps1, run on Central to manage Control Center logins