Build an Ecosystem¶
An ecosystem is your lab's FLEX setup in one TOML manifest: the packages to install plus every setting. Share the file; new members run one command.
flex ecosystem use mylab.toml
The manifest¶
[ecosystem]
name = "mylab"
packages = ["flex-datatypes", "flex-drivers"] # installed on activation
[lab]
name = "mylab"
station = "cryo1"
[db]
backend = "sqlite" # or "postgres" with dsn = "postgresql://..."
[storage]
backend = "local" # or "nextcloud" with url/user (+ NEXTCLOUD_PASSWORD env)
[data]
writer = "hdf5" # or "tdms"
root = "D:/data"
[comms]
backend = "none" # or "asana" (flex-asana) -- see its package docstring for config
[hooks] # dotted refs, subscribed to experiment events
on_experiment_end = ["some_package.hooks:notify"]
[drivers]
enabled = ["srs.sr7270"]
[stations.cryo1.instruments.lockin]
driver = "srs.sr7270"
address = "USB0::0x0A2D::0x001B::12345::RAW"
Every section is optional — omit it and the default applies. Backends may
define their own extra keys (like dsn above); they pass straight through.
How the configuration is found¶
- explicit path (
Experiment(config=...)/load_config(path)) - the
FLEX_CONFIGenvironment variable ./flex.tomlin the working directory- the activated config (
%LOCALAPPDATA%/flex/config.toml) - nothing → pure defaults (SQLite + HDF5 + local files)
flex ecosystem show prints the resolved result; flex ecosystem validate
mylab.toml checks a manifest and whether its components are installed.
Stations¶
[stations.*] describes which instruments live where. Then:
with Experiment("jane") as exp:
exp.load_station("cryo1") # constructs and registers every instrument
exp.lockin.x() # ready to use
flex instruments --probe test-connects everything from the shell.
Extending FLEX itself¶
Labs add their own components as normal Python packages:
- a driver package:
flex new package flex-drivers-mylabscaffolds one — fill drivers in, list them in itsCATALOG, and they appear inflex list --drivers; - a DB backend / data writer / storage backend / comms backend: subclass
MetadataStore,DataWriter,StorageBackend, orCommsBackendfromflex-coreand export a{name: "module:Class"}registry dict from your package — the name you register is what goes in the manifest; - hooks: any function
fn(event, experiment, **payload), referenced from[hooks].
To make a component discoverable by flex install/flex list without
editing an installed package, add it to a catalog.local.json next to your
active ecosystem config, e.g.
{"flex-drivers-mylab": {"registries": {"drivers": "flex_drivers_mylab:CATALOG"}}}.
The FLEX repo hosts official packages in packages/; PRs welcome — the
LevyLab drivers (flex_drivers.levylab) alongside flex-datatypes,
flex-nextcloud, flex-asana are the reference implementation.
To make your own lab's manifest activatable by bare name (flex ecosystem use
mylab) rather than a full path, drop it in this repo's own ecosystems/
folder (not inside any package — see flex.pkgmanager.ecosystems). Only
default.toml ships inside flex-core itself; everything else here is this
repo's own content, so a fork can add, remove, or replace manifests without
touching core at all.