Working with MADSci experiment modalities and the experiment lifecycle. Use when creating, modifying, or debugging experiments using ExperimentScript, ExperimentNotebook, ExperimentTUI, or ExperimentNode. Use when this capability is needed.
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Working with MADSci experiment modalities and the experiment lifecycle. Use when creating, modifying, or debugging experiments using ExperimentScript, ExperimentNotebook, ExperimentTUI, or ExperimentNode. Use when this capability is needed.
metadata
{"author":"AD-SDL"}
MADSci Experiments
MADSci provides four experiment modalities, all built on ExperimentBase which uses MadsciClientMixin (composition, not RestNode inheritance). Choose the right modality for your use case, then implement run_experiment().
Key design choice: ExperimentBase uses composition (MadsciClientMixin), not inheritance from RestNode. Only ExperimentNode creates a RestNode internally when it needs server capabilities.
ExperimentDesign vs Experiment
ExperimentDesign: Template/blueprint. Defines experiment_name, description, resource_conditions. Reusable across runs. Can be loaded from YAML.
Experiment: Runtime instance. Has experiment_id (ULID), status, timestamps, ownership. Created by start_experiment_run().
from madsci.common.types.experiment_types import ExperimentDesign
design = ExperimentDesign(
experiment_name="Synthesis Optimization",
experiment_description="Optimize reaction conditions for compound X",
)
# Or load from YAML
design = ExperimentDesign.from_yaml("experiment_design.yaml")
ExperimentScript (Simplest Modality)
from madsci.experiment_application.experiment_script import ExperimentScript
from madsci.common.types.experiment_types import ExperimentDesign
classSynthesisExperiment(ExperimentScript):
experiment_design = ExperimentDesign(
experiment_name="Synthesis Run",
experiment_description="Automated synthesis workflow",
)
defrun_experiment(self, sample_id: str = "default", cycles: int = 3) -> dict:
"""Core experiment logic. Called within manage_experiment() context."""
results = []
for i inrange(cycles):
result = self.workcell_client.run_workflow(
"synthesis", parameters={"sample_id": sample_id, "cycle": i}
)
results.append(result)
self.logger.info("Cycle completed", cycle=i, result=result)
return {"sample_id": sample_id, "results": results}
if __name__ == "__main__":
SynthesisExperiment.main(sample_id="ABC123", cycles=5)
Entry points:
run(*args, **kwargs): Instance method. Merges config args with passed args.
main(*args, **kwargs): Class method. Creates instance and calls run().
Config class:ExperimentScriptConfig adds run_args and run_kwargs fields for CLI/env configuration.
ExperimentNotebook (Jupyter)
Designed for cell-by-cell interactive use in Jupyter notebooks.
Interactive terminal interface with pause/cancel controls via Textual.
from madsci.experiment_application.experiment_tui import ExperimentTUI
from madsci.common.types.experiment_types import ExperimentDesign
classOperatorExperiment(ExperimentTUI):
experiment_design = ExperimentDesign(
experiment_name="Operator-Assisted Synthesis",
)
defrun_experiment(self) -> dict:
results = []
for step inrange(10):
self.check_experiment_status() # Handles pause/cancel locally
result = self.workcell_client.run_workflow("step", parameters={"n": step})
results.append(result)
return {"steps_completed": len(results)}
if __name__ == "__main__":
OperatorExperiment().run_tui()
Thread-safe controls:
request_pause() / request_resume() / request_cancel(): Called from TUI thread
check_experiment_status(): Called in experiment thread. Uses threading.Event (no server round-trips). Raises ExperimentCancelledError if cancelled. Blocks while paused.
withself.manage_experiment(run_name="Run 1") as exp:
# Experiment started, logging context established
result = exp.workcell_client.run_workflow("my_workflow")
# On success: end_experiment(COMPLETED) called automatically# On exception: handle_exception() called, then re-raised
The context manager:
Calls start_experiment_run() -> registers with Experiment Manager
Sets up hierarchical logging context (experiment_id, experiment_name, run_name, experiment_type)
Templates in src/madsci_common/madsci/common/bundled_templates/experiment/:
script/ -> {name}.py
notebook/ -> {name}.ipynb
tui/ -> {name}_tui.py
node/ -> {name}_node.py
Checking Experiment Status (Pause/Cancel)
Call check_experiment_status() at natural checkpoints in long-running experiments:
defrun_experiment(self):
for batch in batches:
self.check_experiment_status() # Blocks if paused, raises if cancelled
process(batch)
ExperimentTUI behavior: Uses local threading.Event (no network calls).
Other modalities: Polls Experiment Manager with exponential backoff (5s -> 60s). Logs "Still waiting" every 5 minutes.
Common Pitfalls
Override run_experiment(), not run(): run() handles lifecycle; run_experiment() is your logic
Use manage_experiment() context manager: Ensures proper start/end and exception handling
ULID not UUID: Use new_ulid_str() for any IDs you generate
Notebook start/end: Must call start() before run_workflow() and end() when done
TUI requires textual: pip install textual or it raises ImportError
ExperimentApplication is deprecated: Use the 4 modalities above instead (removal in v0.8.0)
Client URLs: Set via config, env vars (EXPERIMENT_EVENT_SERVER_URL), or lab context (service discovery via lab_server_url)
AnyUrl trailing slash: Pydantic's AnyUrl always adds a trailing slash