Launcher Architecture
Experiment Flow Diagram
![digraph experiment_flow {
rankdir=LR;
node [shape=box, style=filled, fillcolor=lightgray];
ParamFile [label="Parameter File (JSON)", shape=note, fillcolor=lightyellow];
RigConfigFile [label="Rig Config (TOML)", shape=note, fillcolor=lightyellow];
RuntimePrompt [label="Runtime Prompts", shape=note, fillcolor=lightyellow];
Launcher [label="Launcher\n(flow orchestrator)", shape=box, fillcolor=lightblue, style="filled,bold"];
PrePipeline [label="Pre-Acquisition Pipeline\n(modules)"];
Acquisition [label="Acquisition Subprocess\n(Bonsai, MATLAB, Python, etc.)"];
PostPipeline [label="Post-Acquisition Pipeline\n(modules)"];
SessionFolder [label="Session Folder\n(all logs, metadata, data)", shape=folder, fillcolor=yellow];
ParamFile -> Launcher;
RigConfigFile -> Launcher;
RuntimePrompt -> Launcher;
Launcher -> PrePipeline;
PrePipeline -> SessionFolder;
Launcher -> Acquisition;
Acquisition -> SessionFolder;
Launcher -> PostPipeline;
PostPipeline -> SessionFolder;
Launcher -> SessionFolder; // <-- Launcher writes directly to session folder
}](_images/graphviz-90407c9ec7bb24d4bbbd3a774548cad2fd9ebd01.png)
Note
The launcher manages the entire experiment flow: merging parameters, prompting for missing info, running pre-acquisition modules, launching the acquisition subprocess, and running post-acquisition modules. All steps, including the launcher itself, write to the session folder.
System Architecture Diagram
![digraph launcher_architecture {
rankdir=LR;
node [shape=box, style=filled, fillcolor=lightgray];
# Core entities
ParamFile [label="Parameter File (JSON)", shape=note, fillcolor=lightyellow];
BaseLauncher [label="BaseLauncher\n(core orchestration)", fillcolor=lightblue, style="filled,bold"];
InterfaceAdapter [label="Interface Adapter\n(Bonsai / MATLAB / Python / Custom)", fillcolor=white, style="filled"];
PreModules [label="Pre-Acquisition Modules\n(mouse weight prompts, etc.)"];
PostModules [label="Post-Acquisition Modules\n(session_creator, notes, etc.)"];
AcquisitionProc [label="Acquisition Process\n(external executable)"];
# Utilities
ParamUtils [label="param_utils.py\n(load + prompts)"];
RigConfig [label="rig_config.py\n(rig placeholders)"];
GitManager [label="git_manager.py\n(optional repo mgmt)"];
Logging [label="logging utils\n(session + centralized)"];
# Relationships
ParamFile -> BaseLauncher;
BaseLauncher -> ParamUtils;
ParamUtils -> RigConfig;
BaseLauncher -> PreModules;
BaseLauncher -> InterfaceAdapter;
InterfaceAdapter -> AcquisitionProc [label="subprocess spawn"];
BaseLauncher -> PostModules;
BaseLauncher -> GitManager;
BaseLauncher -> Logging;
PreModules -> AcquisitionProc [style=dashed, label="optional signals"];
PostModules -> AcquisitionProc [style=dashed, label="optional logs"];
# Pre and post remain independent
PreModules [group=pre];
PostModules [group=post];
}](_images/graphviz-e8d75d7e5cd669fbfff176958cd59ef5189e7dac.png)
Note
A single BaseLauncher orchestrates experiments. Lightweight interface adapters handle only subprocess creation; extend or override _create_process for custom environments.
Launcher Flow Overview
Parameter File Input: - The user provides a parameter file (JSON) to the launcher.
Rig Config Merge: - The launcher loads the rig config (TOML) and merges it with the parameter file (parameters override rig config).
Runtime Prompts: - The launcher interactively prompts for any missing required values, which override both param file and rig config.
Pre-Acquisition Pipeline: - The launcher runs each pre-acquisition module in order, passing the merged parameter file. Each module can read/write to the session folder.
Acquisition Subprocess: - The launcher starts the main experiment process (Bonsai, MATLAB, Python, etc.) with the merged parameters. The subprocess writes data and logs to the session folder.
Post-Acquisition Pipeline: - After acquisition, the launcher runs each post-acquisition module in order, again passing the merged parameter file. These modules can generate session files, enhance metadata, and write results to the session folder.
All steps (launcher, pre-acquisition modules, acquisition subprocess, post-acquisition modules) write logs, metadata, and data to the session folder.
Repository Folder Structure
src/openscope_experimental_launcher/: Main package source code
launchers/: CoreBaseLauncherand optional custom subclasses
interfaces/: Lightweight interface adapters for spawning external processes
pre_acquisition/: Modular pre-acquisition pipeline modules (mouse weight prompts, etc.)
post_acquisition/: Modular post-acquisition pipeline modules (session creation, notes, enhancement, etc.)
utils/: Shared utilities (configuration, git, logging, etc.)
params/: Example and project-specific parameter files (JSON)tests/: Unit and integration tests for all core logic and modulesdocs/: Documentation sources (reStructuredText, Sphinx, and build scripts)run_launcher.py: CLI entry point for running experiments with a parameter filerun_module.py: CLI entry point for running any pipeline module directlysetup.py,pyproject.toml: Packaging and build configurationREADME.md,LICENSE, etc.: Project metadata and top-level documentation
Philosophy: Modular Pre- and Post-Acquisition
The OpenScope launcher is designed for maximum flexibility and reproducibility. All experiment-specific logic (e.g., mouse weight prompts, experiment notes, data enhancement) is handled by modular pipeline modules, not the launcher core. This ensures:
Generic launchers for each language/software (Bonsai, MATLAB, Python)
All pre- and post-acquisition steps are modular and easily extended
Parameter files define which modules run for each experiment
Symmetry: Pre- and post-acquisition are handled identically, via ordered module lists
How Modules Are Inserted
To add a pre- or post-acquisition step, simply add the module name to the appropriate list in your parameter file:
{
"pre_acquisition_pipeline": ["mouse_weight_pre_prompt"],
"post_acquisition_pipeline": ["mouse_weight_post_prompt", "experiment_notes_post_prompt"],
...
}
Each module is a Python file in src/openscope_experimental_launcher/pre_acquisition/ or post_acquisition/, and must accept a param_file argument and return 0 for success, 1 for failure.
For more, see the Pre-Acquisition Modules and Post-Acquisition Modules sections of Pre- and Post-Acquisition Modules, and the Contributing to OpenScope Experimental Launcher guide.