Lab
hashgraph-online/awesome-codex-plugins
Build a Game Lab for one mechanic of a studio's game (the jump, a hit, a dash, a drift, a landing) and iterate on how it FEELS with the creator, side by side.
Guide for adding new workstations to Uni-Lab-OS (接入新工作站). An agent skill from deepmodeling/Uni-Lab-OS.
$ npx skills add deepmodeling/Uni-Lab-OS --skill add-workstation -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install deepmodeling/Uni-Lab-OS add-workstation --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/deepmodeling/Uni-Lab-OS.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.cursor/skills/add-workstation .claude/skills/add-workstation && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "add-workstation" agent skill from https://github.com/deepmodeling/Uni-Lab-OS/tree/main/.cursor/skills/add-workstation into .claude/skills/add-workstation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-workstation", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/deepmodeling/Uni-Lab-OS/tree/main/.cursor/skills/add-workstationType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add deepmodeling/Uni-Lab-OS --skill add-workstation -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install deepmodeling/Uni-Lab-OS add-workstation --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/deepmodeling/Uni-Lab-OS.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.cursor/skills/add-workstation .agents/skills/add-workstation && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "add-workstation" agent skill from https://github.com/deepmodeling/Uni-Lab-OS/tree/main/.cursor/skills/add-workstation into .agents/skills/add-workstation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-workstation", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add deepmodeling/Uni-Lab-OS --skill add-workstation -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install deepmodeling/Uni-Lab-OS add-workstation --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/deepmodeling/Uni-Lab-OS.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.cursor/skills/add-workstation .cursor/skills/add-workstation && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "add-workstation" agent skill from https://github.com/deepmodeling/Uni-Lab-OS/tree/main/.cursor/skills/add-workstation into .cursor/skills/add-workstation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-workstation", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/deepmodeling/Uni-Lab-OS.git --path .cursor/skills/add-workstation--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add deepmodeling/Uni-Lab-OS --skill add-workstation -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install deepmodeling/Uni-Lab-OS add-workstation --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/deepmodeling/Uni-Lab-OS.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.cursor/skills/add-workstation .gemini/skills/add-workstation && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "add-workstation" agent skill from https://github.com/deepmodeling/Uni-Lab-OS/tree/main/.cursor/skills/add-workstation into .gemini/skills/add-workstation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-workstation", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install deepmodeling/Uni-Lab-OS add-workstationInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add deepmodeling/Uni-Lab-OS --skill add-workstation -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/deepmodeling/Uni-Lab-OS.git skills-src && mkdir -p .github/skills && cp -r skills-src/.cursor/skills/add-workstation .github/skills/add-workstation && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "add-workstation" agent skill from https://github.com/deepmodeling/Uni-Lab-OS/tree/main/.cursor/skills/add-workstation into .github/skills/add-workstation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-workstation", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add deepmodeling/Uni-Lab-OS --skill add-workstation -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install deepmodeling/Uni-Lab-OS add-workstation --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/deepmodeling/Uni-Lab-OS.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.cursor/skills/add-workstation .opencode/skills/add-workstation && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "add-workstation" agent skill from https://github.com/deepmodeling/Uni-Lab-OS/tree/main/.cursor/skills/add-workstation into .opencode/skills/add-workstation/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-workstation", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
add-workstationGuide for adding new workstations to Uni-Lab-OS (接入新工作站). An agent skill from deepmodeling/Uni-Lab-OS.
Add Workstation is an agent skill from deepmodeling/Uni-Lab-OS. Guide for adding new workstations to Uni-Lab-OS (接入新工作站). Uses @device decorator + AST auto-scanning. Walks through workstation type, sub-device composition, driver creation, deck setup, and graph file. Use when the user wants to add a workstation, create a workstation driver, configure a station with sub-devices, or mentions 工作站/工站/station/workstation.
Its SKILL.md is about 4.4k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `reference.md`).
The repository describes itself as: A Platform for Laboratory Automation. The licence is GPL-3.0.
6 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 43923ec. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pythonFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Add Workstation loads about 4.4k tokens when it runs. Until then it costs about 93 tokens; SKILL.md has 479 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from deepmodeling/Uni-Lab-OS at commit 43923ec, republished under its GPL-3.0 licence (© deepmodeling). 479 words, ~4,438 tokens.
.claude/skills/add-workstation/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.工作站(workstation)是组合多个子设备的大型设备,拥有独立的物料管理系统和工作流引擎。使用 @device 装饰器注册,AST 自动扫描生成注册表。
| 类型 | 基类 | 适用场景 |
|---|---|---|
| Protocol 工作站 | ProtocolNode | 标准化学操作协议(泵转移、过滤等) |
| 外部系统工作站 | WorkstationBase | 与外部 LIMS/MES 对接 |
| 硬件控制工作站 | WorkstationBase | 直接控制 PLC/硬件 |
工作站也使用 @device 装饰器注册,参数与普通设备一致:
@device(
id="my_workstation", # 注册表唯一标识(必填)
category=["workstation"], # 分类标签
description="我的工作站",
)如果一个工作站类支持多个具体变体,可使用 ids / id_meta,与设备的用法相同(参见 add-device SKILL)。
import logging
from typing import Dict, Any, Optional
from pylabrobot.resources import Deck
from unilabos.registry.decorators import device, topic_config, not_action
from unilabos.devices.workstation.workstation_base import WorkstationBase
try:
from unilabos.ros.nodes.presets.workstation import ROS2WorkstationNode
except ImportError:
ROS2WorkstationNode = None
@device(id="my_workstation", category=["workstation"], description="我的工作站")
class MyWorkstation(WorkstationBase):
_ros_node: "ROS2WorkstationNode"
def __init__(self, config=None, deck=None, protocol_type=None, **kwargs):
super().__init__(deck=deck, **kwargs)
self.config = config or {}
self.logger = logging.getLogger("MyWorkstation")
self.api_host = self.config.get("api_host", "")
self._status = "Idle"
@not_action
def post_init(self, ros_node: "ROS2WorkstationNode"):
super().post_init(ros_node)
self._ros_node = ros_node
async def scheduler_start(self, **kwargs) -> Dict[str, Any]:
"""注册为工作站动作"""
return {"success": True}
async def create_order(self, json_str: str, **kwargs) -> Dict[str, Any]:
"""注册为工作站动作"""
return {"success": True}
@property
@topic_config()
def workflow_sequence(self) -> str:
return "[]"
@property
@topic_config()
def material_info(self) -> str:
return "{}"直接使用 ProtocolNode,通常不需要自定义驱动类:
from unilabos.devices.workstation.workstation_base import ProtocolNode在图文件中配置 protocol_type 即可。
工站初始化子设备后,所有子设备实例存储在 self._ros_node.sub_devices 字典中(key 为设备 id,value 为 ROS2DeviceNode 实例)。工站的驱动类可以直接获取子设备实例来调用其方法:
# 在工站驱动类的方法中访问子设备
sub = self._ros_node.sub_devices["pump_1"]
# .driver_instance — 子设备的驱动实例(即设备 Python 类的实例)
sub.driver_instance.some_method(arg1, arg2)
# .ros_node_instance — 子设备的 ROS2 节点实例
sub.ros_node_instance._action_value_mappings # 查看子设备支持的 action常见用法:
class MyWorkstation(WorkstationBase):
def my_protocol(self, **kwargs):
# 获取子设备驱动实例
pump = self._ros_node.sub_devices["pump_1"].driver_instance
heater = self._ros_node.sub_devices["heater_1"].driver_instance
# 直接调用子设备方法
pump.aspirate(volume=100)
heater.set_temperature(80)参考实现:
unilabos/devices/workstation/bioyond_studio/reaction_station/reaction_station.py中通过self._ros_node.sub_devices.get(reactor_id)获取子反应器实例并更新数据。
硬件控制型工作站通常需要通过串口(Serial)、Modbus 等通信协议控制多个子设备。Uni-Lab-OS 通过 通信设备代理 机制实现端口共享:一个串口只创建一个 serial 节点,多个子设备共享这个通信实例。
ROS2WorkstationNode 初始化时分两轮遍历子设备(workstation.py):
第一轮 — 初始化所有子设备:按 children 顺序调用 initialize_device(),通信设备(serial_ / io_ 开头的 id)优先完成初始化,创建 serial.Serial() 实例。其他子设备此时 self.hardware_interface = "serial_pump"(字符串)。
第二轮 — 代理替换:遍历所有已初始化的子设备,读取子设备的 _hardware_interface 配置:
hardware_interface = d.ros_node_instance._hardware_interface
# → {"name": "hardware_interface", "read": "send_command", "write": "send_command"}name 字段对应的属性值:name_value = getattr(driver, hardware_interface["name"])name_value 是字符串且该字符串是某个子设备的 id → 触发代理替换read/write 方法setattr(driver, read_method, _read) 将通信设备的方法绑定到子设备上因此:
"serial_pump")serial_ 或 io_ 开头(否则第一轮不会被识别为通信设备)children 列表中排在最前面,确保先初始化from unilabos.registry.decorators import HardwareInterface
HardwareInterface(
name="hardware_interface", # __init__ 中接收通信实例的属性名
read="send_command", # 通信设备上暴露的读方法名
write="send_command", # 通信设备上暴露的写方法名
extra_info=["list_ports"], # 可选:额外暴露的方法
)name 字段的含义:对应设备类 __init__ 中,用于保存通信实例的属性名。系统据此知道要替换哪个属性。大部分设备直接用 "hardware_interface",也可以自定义(如 "io_device_port")。
from unilabos.registry.decorators import device, HardwareInterface
@device(
id="my_pump",
category=["pump_and_valve"],
hardware_interface=HardwareInterface(
name="hardware_interface",
read="send_command",
write="send_command",
),
)
class MyPump:
def __init__(self, port=None, address="1", **kwargs):
# name="hardware_interface" → 系统替换 self.hardware_interface
self.hardware_interface = port # 初始为字符串 "serial_pump",启动后被替换为 Serial 实例
self.address = address
def send_command(self, command: str):
full_command = f"/{self.address}{command}\r\n"
self.hardware_interface.write(bytearray(full_command, "ascii"))
return self.hardware_interface.read_until(b"\n")@device(
id="solenoid_valve",
category=["pump_and_valve"],
hardware_interface=HardwareInterface(
name="io_device_port", # 自定义属性名 → 系统替换 self.io_device_port
read="read_io_coil",
write="write_io_coil",
),
)
class SolenoidValve:
def __init__(self, io_device_port: str = None, **kwargs):
# name="io_device_port" → 图文件 config 中用 "io_device_port": "io_board_1"
self.io_device_port = io_device_port # 初始为字符串,系统替换为 Modbus 实例serial 是 Uni-Lab-OS 内置的通信代理设备,代码位于 unilabos/ros/nodes/presets/serial_node.py:
from serial import Serial, SerialException
from threading import Lock
class ROS2SerialNode(BaseROS2DeviceNode):
def __init__(self, device_id, registry_name, port: str, baudrate: int = 9600, **kwargs):
self.port = port
self.baudrate = baudrate
self._hardware_interface = {
"name": "hardware_interface",
"write": "send_command",
"read": "read_data",
}
self._query_lock = Lock()
self.hardware_interface = Serial(baudrate=baudrate, port=port)
BaseROS2DeviceNode.__init__(
self, driver_instance=self, registry_name=registry_name,
device_id=device_id, status_types={}, action_value_mappings={},
hardware_interface=self._hardware_interface, print_publish=False,
)
self.create_service(SerialCommand, "serialwrite", self.handle_serial_request)
def send_command(self, command: str):
with self._query_lock:
self.hardware_interface.write(bytearray(f"{command}\n", "ascii"))
return self.hardware_interface.read_until(b"\n").decode()
def read_data(self):
with self._query_lock:
return self.hardware_interface.read_until(b"\n").decode()在图文件中使用 "class": "serial" 即可创建串口代理:
{
"id": "serial_pump",
"class": "serial",
"parent": "my_station",
"config": { "port": "COM7", "baudrate": 9600 }
}通信设备必须在 children 列表中排在最前面,确保先于其他子设备初始化:
{
"nodes": [
{
"id": "my_station",
"class": "workstation",
"children": ["serial_pump", "pump_1", "pump_2"],
"config": { "protocol_type": ["PumpTransferProtocol"] }
},
{
"id": "serial_pump",
"class": "serial",
"parent": "my_station",
"config": { "port": "COM7", "baudrate": 9600 }
},
{
"id": "pump_1",
"class": "syringe_pump_with_valve.runze.SY03B-T08",
"parent": "my_station",
"config": { "port": "serial_pump", "address": "1", "max_volume": 25.0 }
},
{
"id": "pump_2",
"class": "syringe_pump_with_valve.runze.SY03B-T08",
"parent": "my_station",
"config": { "port": "serial_pump", "address": "2", "max_volume": 25.0 }
}
],
"links": [
{
"source": "pump_1",
"target": "serial_pump",
"type": "communication",
"port": { "pump_1": "port", "serial_pump": "port" }
},
{
"source": "pump_2",
"target": "serial_pump",
"type": "communication",
"port": { "pump_2": "port", "serial_pump": "port" }
}
]
}| 协议 | config 参数 | 依赖包 | 通信设备 class |
|---|---|---|---|
| Serial (RS232/RS485) | port, baudrate | pyserial | serial |
| Modbus RTU | port, baudrate, slave_id | pymodbus | device_comms/modbus_plc/ |
| Modbus TCP | host, port, slave_id | pymodbus | device_comms/modbus_plc/ |
| TCP Socket | host, port | stdlib | 自定义 |
| HTTP API | url, token | requests | device_comms/rpc.py |
参考实现:unilabos/test/experiments/Grignard_flow_batchreact_single_pumpvalve.json
系统根据设备节点 config.deck 的写法,自动反序列化 Deck 实例后传入 __init__ 的 deck 参数。目前 deck 是固定字段名,只支持一个主 Deck。建议一个设备拥有一个台面,台面上抽象二级、三级子物料。
有两种初始化模式:
config.deck 直接包含 _resource_type + _resource_child_name,系统先用 Deck 节点的 config 调用 Deck 类的 __init__ 反序列化,再将实例传入设备的 deck 参数。子物料随 Deck 的 children 一起反序列化。
"config": {
"deck": {
"_resource_type": "unilabos.devices.liquid_handling.prcxi.prcxi:PRCXI9300Deck",
"_resource_child_name": "PRCXI_Deck"
}
}config.deck 用 data 包裹一层,系统走 deserialize 路径,可传入更多参数(如 allow_marshal 等):
"config": {
"deck": {
"data": {
"_resource_child_name": "YB_Bioyond_Deck",
"_resource_type": "unilabos.resources.bioyond.decks:BIOYOND_YB_Deck"
}
}
}没有特殊需求时推荐 init 初始化。
| 字段 | 说明 |
|---|---|
_resource_type | Deck 类的完整模块路径(module:ClassName) |
_resource_child_name | 对应图文件中 Deck 节点的 id,建立父子关联 |
def __init__(self, config=None, deck=None, protocol_type=None, **kwargs):
super().__init__(deck=deck, **kwargs)
# deck 已经是反序列化后的 Deck 实例
# → PRCXI9300Deck / BIOYOND_YB_Deck 等Deck 节点作为设备的 children 之一,parent 指向设备 id:
{
"id": "PRCXI_Deck",
"parent": "PRCXI",
"type": "deck",
"class": "",
"children": [],
"config": {
"type": "PRCXI9300Deck",
"size_x": 542, "size_y": 374, "size_z": 0,
"category": "deck",
"sites": [...]
},
"data": {}
}config 中的字段会传入 Deck 类的 __init__(因此 __init__ 必须能接受所有 serialize() 输出的字段)children 初始为空时,由同步器或手动初始化填充config.type 填 Deck 类名如果 Deck 节点的 children 为空,工作站需在 post_init 或首次同步时自行初始化内容:
@not_action
def post_init(self, ros_node):
super().post_init(ros_node)
if self.deck and not self.deck.children:
self._initialize_default_deck()
def _initialize_default_deck(self):
from my_labware import My_TipRack, My_Plate
self.deck.assign_child_resource(My_TipRack("T1"), spot=0)
self.deck.assign_child_resource(My_Plate("T2"), spot=1)当工作站对接外部系统(LIMS/MES)时,需要实现 ResourceSynchronizer 处理双向物料同步:
from unilabos.devices.workstation.workstation_base import ResourceSynchronizer
class MyResourceSynchronizer(ResourceSynchronizer):
def sync_from_external(self) -> bool:
"""从外部系统同步到 self.workstation.deck"""
external_data = self._query_external_materials()
# 以外部工站为准:根据外部数据反向创建 PLR 资源实例
for item in external_data:
cls = self._resolve_resource_class(item["type"])
resource = cls(name=item["name"], **item["params"])
self.workstation.deck.assign_child_resource(resource, spot=item["slot"])
return True
def sync_to_external(self, resource) -> bool:
"""将 UniLab 侧物料变更同步到外部系统"""
# 以 UniLab 为准:将 PLR 资源转为外部格式并推送
external_format = self._convert_to_external(resource)
return self._push_to_external(external_format)
def handle_external_change(self, change_info) -> bool:
"""处理外部系统主动推送的变更"""
return True同步策略取决于业务场景:
sync_to_external 推送到外部系统在工作站 post_init 中初始化同步器:
@not_action
def post_init(self, ros_node):
super().post_init(ros_node)
self.resource_synchronizer = MyResourceSynchronizer(self)
self.resource_synchronizer.sync_from_external()资源类需正确实现序列化,系统据此完成持久化和前端同步。
serialize() — 输出资源的结构信息(config 层),反序列化时作为 __init__ 的入参回传。因此 **__init__ 必须通过 **kwargs接受serialize() 输出的所有字段**,即使当前不使用:
class MyDeck(Deck):
def __init__(self, name, size_x, size_y, size_z,
sites=None, # serialize() 输出的字段
rotation=None, # serialize() 输出的字段
barcode=None, # serialize() 输出的字段
**kwargs): # 兜底:接受所有未知的 serialize 字段
super().__init__(size_x, size_y, size_z, name)
# ...
def serialize(self) -> dict:
data = super().serialize()
data["sites"] = [...] # 自定义字段
return dataserialize_state() — 输出资源的运行时状态(data 层),用于持久化可变信息。data 中的内容会被正确保存和恢复:
class MyPlate(Plate):
def __init__(self, name, size_x, size_y, size_z,
material_info=None, **kwargs):
super().__init__(name, size_x, size_y, size_z, **kwargs)
self._unilabos_state = {}
if material_info:
self._unilabos_state["Material"] = material_info
def serialize_state(self) -> Dict[str, Any]:
data = super().serialize_state()
data.update(self._unilabos_state)
return data关键要点:
serialize() 输出的所有字段都会作为 config 回传到 __init__,所以 __init__ 必须能接受它们(显式声明或 **kwargs)serialize_state() 输出的 data 用于持久化运行时状态(如物料信息、液体量等)_unilabos_state 中只存可 JSON 序列化的基本类型(str, int, float, bool, list, dict, None)子物料(Bottle、Plate、TipRack 等)放到 Deck 上后,系统会自动将其同步到前端的 Deck 视图。只需保证资源类正确实现了 serialize() / serialize_state() 和反序列化即可。
{
"nodes": [
{
"id": "my_station",
"type": "device",
"class": "my_workstation",
"config": {
"deck": {
"_resource_type": "unilabos.resources.my_module:MyDeck",
"_resource_child_name": "my_deck"
},
"host": "10.20.30.1",
"port": 9999
}
},
{
"id": "my_deck",
"parent": "my_station",
"type": "deck",
"class": "",
"children": [],
"config": {
"type": "MyLabDeck",
"size_x": 542,
"size_y": 374,
"size_z": 0,
"category": "deck",
"sites": [
{
"label": "T1",
"visible": true,
"occupied_by": null,
"position": { "x": 0, "y": 0, "z": 0 },
"size": { "width": 128.0, "height": 86, "depth": 0 },
"content_type": ["plate", "tip_rack", "tube_rack", "adaptor"]
}
]
},
"data": {}
}
],
"edges": []
}Deck 节点要点:
config.type 填 Deck 类名(如 "PRCXI9300Deck")config.sites 完整列出所有 site(从 Deck 类的 serialize() 输出获取)children 初始为空(由同步器或手动初始化填充)config.deck._resource_type 指向 Deck 类的完整模块路径子设备按标准设备接入流程创建(参见 add-device SKILL),使用 @device 装饰器。
子设备约束:
parent 指向工作站 IDchildren 数组中列出__init__ 必须接受 deck 和 **kwargs — WorkstationBase.**init**需要deck 参数config.deck._resource_type 反序列化传入 — 不要在 __init__ 中手动创建 Deckpost_init 中检查并填充默认物料ResourceSynchronizer — sync_from_external / sync_to_externalself._children 访问子设备 — 不要自行维护子设备引用post_init 中启动后台服务 — 不要在 __init__ 中启动网络连接await self._ros_node.sleep() — 禁止 time.sleep() 和 asyncio.sleep()@not_action 标记非动作方法 — post_init, initialize, cleanup# 模块可导入
python -c "from unilabos.devices.workstation.<name>.<name> import <ClassName>"
# 启动测试(AST 自动扫描)
unilab -g <graph>.json| 工作站 | 驱动类 | 类型 |
|---|---|---|
| Protocol 通用 | ProtocolNode | Protocol |
| Bioyond 反应站 | BioyondReactionStation | 外部系统 |
| 纽扣电池组装 | CoinCellAssemblyWorkstation | 硬件控制 |
参考路径:unilabos/devices/workstation/ 目录下各工作站实现。
© deepmodeling, GPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in .cursor/skills/add-workstation of deepmodeling/Uni-Lab-OS.
Open the folder on GitHubat commit 43923ec
Add Workstation next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Add Workstation this skilldeepmodeling/Uni-Lab-OS | 178 | — | ~4.4k | Automated safety check: Pass | GPL-3.0 | |
| Labhashgraph-online/awesome-codex-plugins | 1.2k | — | ~2.7k | Automated safety check: Pass | Apache-2.0 | |
| WorkstationLeoYeAI/openclaw-master-skills | 2.2k | — | ~4.4k | Automated safety check: Pass | MIT | |
| Ginkgo Cloud LabK-Dense-AI/scientific-agent-skills | 48k | 1 repos | ~2.8k | Automated safety check: Pass | MIT | |
| Bambu Lab Print Handoffearthtojake/text-to-cad | 18k | — | ~861 | Automated safety check: Pass | MIT | |
| Mesh Labpermissionlesstech/bitchat-android | 7.7k | — | ~2.9k | Automated safety check: Pass | GPL-3.0 |
hashgraph-online/awesome-codex-plugins
Build a Game Lab for one mechanic of a studio's game (the jump, a hit, a dash, a drift, a landing) and iterate on how it FEELS with the creator, side by side.
LeoYeAI/openclaw-master-skills
Control Varie Workstation sessions (Claude Code multi-session orchestration).
K-Dense-AI/scientific-agent-skills
Guides protocol selection, input preparation, pricing checks, and browser ordering on Ginkgo Bioworks Cloud Lab (cloud.ginkgo.bio).
earthtojake/text-to-cad
Opens a sliced file in Bambu Connect, or an unsliced model in Bambu Studio, so you can pick a Bambu Lab printer and start the print yourself.
permissionlesstech/bitchat-android
Run, diagnose, and extend bitchat Android Mesh Lab physical-device tests.
mukul975/Anthropic-Cybersecurity-Skills
Design and implement Privileged Access Workstations (PAWs) using the tiered administration model, with device hardening, device compliance enforcement via Microsoft Intune or Group Policy…
deepmodeling/Uni-Lab-OS
Batch submit experiments (notebooks) to the Uni-Lab cloud platform (leap-lab) — list workflows, generate nodeparams from registry schemas, submit multiple rounds, check notebook status.
deepmodeling/Uni-Lab-OS
Create a skill for any Uni-Lab device by extracting action schemas from the device registry.
deepmodeling/Uni-Lab-OS
Query backend workflow list, aggregate all tags, and filter workflows by domain/scenario requirements using tags.
deepmodeling/Uni-Lab-OS
Submit historical experiment results (agentresult) to Uni-Lab cloud platform (leap-lab) notebook — read data files, assemble JSON payload, PUT to cloud API.
deepmodeling/Uni-Lab-OS
Guide for adding new devices to Uni-Lab-OS (接入新设备). An agent skill from deepmodeling/Uni-Lab-OS.
deepmodeling/Uni-Lab-OS
Guide for adding new resources (materials, bottles, carriers, decks, warehouses) to Uni-Lab-OS (添加新物料/资源).
Guide for adding new workstations to Uni-Lab-OS (接入新工作站). An agent skill from deepmodeling/Uni-Lab-OS. Add Workstation is an agent skill from deepmodeling/Uni-Lab-OS. Guide for adding new workstations to Uni-Lab-OS (接入新工作站).
Add Workstation fits situations like: the user wants to add a workstation; create a workstation driver; configure a station with sub-devices; mentions 工作站/工站/station/workstation.
Run `npx skills add deepmodeling/Uni-Lab-OS --skill add-workstation -a claude-code`. Or copy the skill folder (.cursor/skills/add-workstation in deepmodeling/Uni-Lab-OS) into .claude/skills/add-workstation in your project. Claude Code loads it when a task matches its description.
Run `npx skills add deepmodeling/Uni-Lab-OS --skill add-workstation -a codex`. Or copy the skill folder (.cursor/skills/add-workstation in deepmodeling/Uni-Lab-OS) into .agents/skills/add-workstation in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add deepmodeling/Uni-Lab-OS --skill add-workstation -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/add-workstation, .gemini/skills/add-workstation, .github/skills/add-workstation and .opencode/skills/add-workstation in your project.
Going by SKILL.md and its folder, Add Workstation needs the command-line tools its instructions call (python). Our summary lists: Python 3.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Add Workstation is published under the GPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.4k tokens (SKILL.md is roughly 18k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Add Workstation: Lab (hashgraph-online/awesome-codex-plugins, 1.2k stars), Workstation (LeoYeAI/openclaw-master-skills, 2.2k stars), Ginkgo Cloud Lab (K-Dense-AI/scientific-agent-skills, 48k stars) and Bambu Lab Print Handoff (earthtojake/text-to-cad, 18k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
deepmodeling (a GitHub organization) maintains it in deepmodeling/Uni-Lab-OS, which has 178 GitHub stars. The repository holds 10 skills in this directory. The repository was last updated on September 24, 2026.
Source: deepmodeling/Uni-Lab-OS on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.