Files
Uni-Lab-OS/AGENTS.md
Xuwznln c001f6a151 v0.10.19
fast registry load

minor fix on skill & registry

stripe ros2 schema desc
add create-device-skill

new registry system backwards to yaml

remove not exist resource

new registry sys
exp. support with add device

add ai conventions

correct raise create resource error

ret info fix revert

ret info fix

fix prcxi check

add create_resource schema

re signal host ready event

add websocket connection timeout and improve reconnection logic

add open_timeout parameter to websocket connection
add TimeoutError and InvalidStatus exception handling
implement exponential backoff for reconnection attempts
simplify reconnection logic flow

add gzip

change pose extra to any

add isFlapY
2026-03-22 04:25:07 +08:00

5.1 KiB

AGENTS.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Also follow the monorepo-level rules in ../AGENTS.md.

Build & Development

# Install in editable mode (requires mamba env with python 3.11)
pip install -e .
uv pip install -r unilabos/utils/requirements.txt

# Run with a device graph
unilab --graph <graph.json> --config <config.py> --backend ros
unilab --graph <graph.json> --config <config.py> --backend simple  # no ROS2 needed

# Common CLI flags
unilab --app_bridges websocket fastapi    # communication bridges
unilab --test_mode                        # simulate hardware, no real execution
unilab --check_mode                       # CI validation of registry imports
unilab --skip_env_check                   # skip auto-install of dependencies
unilab --visual rviz|web|disable          # visualization mode
unilab --is_slave                         # run as slave node

# Workflow upload subcommand
unilab workflow_upload -f <workflow.json> -n <name> --tags tag1 tag2

# Tests
pytest tests/                              # all tests
pytest tests/resources/test_resourcetreeset.py  # single test file
pytest tests/resources/test_resourcetreeset.py::TestClassName::test_method  # single test

Architecture

Startup Flow

unilab CLI → unilabos/app/main.py:main() → loads config → builds registry → reads device graph (JSON/GraphML) → starts backend thread (ROS2/simple) → starts FastAPI web server + WebSocket client.

Core Layers

Registry (unilabos/registry/): Singleton Registry class discovers and catalogs all device types, resource types, and communication devices from YAML definitions. Device types live in registry/devices/*.yaml, resources in registry/resources/, comms in registry/device_comms/. The registry resolves class paths to actual Python classes via utils/import_manager.py.

Resource Tracking (unilabos/resources/resource_tracker.py): Pydantic-based ResourceDictResourceDictInstanceResourceTreeSet hierarchy. ResourceTreeSet is the canonical in-memory representation of all devices and resources, used throughout the system. Graph I/O is in resources/graphio.py (reads JSON/GraphML device topology files into nx.Graph + ResourceTreeSet).

Device Drivers (unilabos/devices/): 30+ hardware drivers organized by device type (liquid_handling, hplc, balance, arm, etc.). Each driver is a Python class that gets wrapped by ros/device_node_wrapper.py:ros2_device_node() to become a ROS2 node with publishers, subscribers, and action servers.

ROS2 Layer (unilabos/ros/): device_node_wrapper.py dynamically wraps any device class into ROS2DeviceNode (defined in ros/nodes/base_device_node.py). Preset node types in ros/nodes/presets/ include host_node, controller_node, workstation, serial_node, camera. Messages use custom unilabos_msgs (pre-built, distributed via releases).

Protocol Compilation (unilabos/compile/): 20+ protocol compilers (add, centrifuge, dissolve, filter, heatchill, stir, pump, etc.) that transform YAML protocol definitions into executable sequences.

Communication (unilabos/device_comms/): Hardware communication adapters — OPC-UA client, Modbus PLC, RPC, and a universal driver. app/communication.py provides a factory pattern for WebSocket client connections to the cloud.

Web/API (unilabos/app/web/): FastAPI server with REST API (api.py), Jinja2 template pages (pages.py), and HTTP client for cloud communication (client.py). Runs on port 8002 by default.

Configuration System

  • Config classes in unilabos/config/config.py: BasicConfig, WSConfig, HTTPConfig, ROSConfig — all class-level attributes, loaded from Python config files
  • Config files are .py files with matching class names (see config/example_config.py)
  • Environment variables override with prefix UNILABOS_ (e.g., UNILABOS_BASICCONFIG_PORT=9000)
  • Device topology defined in graph files (JSON with node-link format, or GraphML)

Key Data Flow

  1. Graph file → graphio.read_node_link_json()(nx.Graph, ResourceTreeSet, resource_links)
  2. ResourceTreeSet + Registryinitialize_device.initialize_device_from_dict()ROS2DeviceNode instances
  3. Device nodes communicate via ROS2 topics/actions or direct Python calls (simple backend)
  4. Cloud sync via WebSocket (app/ws_client.py) and HTTP (app/web/client.py)

Test Data

Example device graphs and experiment configs are in unilabos/test/experiments/ (not tests/). Registry test fixtures in unilabos/test/registry/.

Code Conventions

  • Code comments and log messages in simplified Chinese
  • Python 3.11+, type hints expected
  • Pydantic models for data validation (resource_tracker.py)
  • Singleton pattern via @singleton decorator (utils/decorator.py)
  • Dynamic class loading via utils/import_manager.py — device classes resolved at runtime from registry YAML paths
  • CLI argument dashes auto-converted to underscores for consistency

Licensing

  • Framework code: GPL-3.0
  • Device drivers (unilabos/devices/): DP Technology Proprietary License — do not redistribute