DD013: Simulation Stack Architecture (The Integration Backbone)¶
- Status: Proposed
- Author: OpenWorm Core Team
- Date: 2026-02-15
- Supersedes: Informal Docker meta-repo approach
- Related: DD001–DD010 (all technical subsystems), DD011 (Contributor Progression), DD012 (RFC Process)
Phase: Infrastructure Bootstrap | Layer: Integration
TL;DR¶
The OpenWorm simulation stack uses Docker Compose to orchestrate five containerized subsystems (neural, muscle, body physics, sensory, visualization) with a shared OME-Zarr data bus. Every contributor runs the same environment via docker compose up, ensuring reproducibility from laptop to CI server. This DD replaces the current monolithic Dockerfile and shell-script approach with a multi-stage Docker build, a declarative openworm.yml configuration system, dependency pinning via versions.lock, and automated CI/CD validation gates.
Context¶
The Gap Between Vision and Execution¶
Design Documents DD001-DD012 specify a rich, multi-tissue, multi-scale organism simulation:
| Subsystem | DD | Primary Repo | Integration Status |
|---|---|---|---|
| Neural circuit (c302) | DD001 | openworm/c302 |
Working — runs via NEURON |
| Muscle model | DD002 | openworm/c302 + openworm/muscle_model |
Working — coupled to c302 |
| Body physics (Sibernetic) | DD003 | openworm/sibernetic |
Working — coupled to c302 via sibernetic_c302.py |
| Mechanical cell identity | DD004 | openworm/sibernetic (future) |
Not started |
| Cell-type specialization | DD005 | openworm/c302 (future) |
Not started |
| Neuropeptides | DD006 | openworm/c302 (future) |
Not started |
| Pharynx | DD007 | New repo TBD | Not started |
| Data integration (OWMeta) | DD008 | openworm/owmeta |
Dormant (last real commit Jul 2024) |
| Intestinal oscillator | DD009 | New repo TBD | Not started |
| Validation framework | DD010, DD021 | openworm/open-worm-analysis-toolbox + openworm/tracker-commons |
Dormant (last commit Jan 2020) — DD021 revival plan |
The openworm/OpenWorm meta-repository is the only place where these subsystems come together as a runnable simulation. It is the architectural backbone of the entire project. And right now, it consists of:
- One Dockerfile
- One Python script (
master_openworm.py) with 3 of 5 steps unimplemented - Four shell scripts (
build.sh,run.sh,run-quick.sh,stop.sh) - No configuration system
- No dependency pinning beyond branch names
- No automated validation
- No docker-compose
- One active maintainer (Neural Circuit L4)
What Actually Runs Today¶
The current simulation pipeline (v0.9.7) executes Step 3 of master_openworm.py:
1. Build Docker image (ubuntu:24.04 + NEURON 8.2.6 + c302 @ ow-0.9.7 + Sibernetic @ ow-0.9.7 + AMD OpenCL SDK)
2. Launch container with X11 forwarding and GPU passthrough
3. Execute sibernetic_c302.py:
a. c302 generates NeuroML network (Level C2, "FW" reference)
b. NEURON simulates neural activity
c. Sibernetic simulates body physics driven by neural output
d. Both run in a coupled loop for 15ms (default)
4. Record video via xvfb + tmux + ffmpeg screen capture
5. Copy outputs (PNGs, WCON, MP4) to shared volume
Steps 1, 2, 4, and 5 of master_openworm.py are stubs ("Not yet implemented"):
- Step 1: Rebuild c302 from latest OWMeta
- Step 2: Execute unit tests
- Step 4: Movement analysis
- Step 5: Report on movement analysis fit
Known Critical Issues¶
| Issue | Impact | GitHub # | Status |
|---|---|---|---|
| Memory leak in plotting/video | OOM kills simulations >2s; 5s sim needs 64GB RAM | #332, #341 | Unfixed |
| No GPU in Docker | OpenCL runs on CPU only; 10× slower than necessary | #320 | Open since 2021 |
| External dependency downloads | AMD SDK from SourceForge; build can break any time | — | Fragile |
| No dependency pinning | apt packages unpinned; c302/Sibernetic pinned to branch name, not commit | #317 | Open since 2021 |
| No virtualenv | pip install --break-system-packages |
#314 | Open since 2021 |
| Fragile video pipeline | xvfb + tmux + ffmpeg screen capture chain | #315, #268 | Open |
| No docker-compose | Raw docker run in shell scripts |
— | Never addressed |
The Contributor Experience Today¶
A contributor who wants to test a change against the full simulation must:
- Fork the relevant repo (e.g.,
c302) - Make their change
- Modify the Dockerfile to point
git cloneat their fork/branch - Build the entire Docker image from scratch (~20 minutes)
- Run the simulation (~10 minutes for 15ms)
- Manually inspect output (PNGs, video)
- No automated validation — must visually compare
This is why most contributors work on subsystems in isolation and never see how their work affects the whole organism.
The Scale of What's Coming¶
The Whole-Organism Modeling Proposal (Phases 1-6) will expand the simulation from:
- 302 identical neurons + body wall muscles + fluid body →
- 128 differentiated neuron types + neuropeptides + pharynx (63 cells) + intestine (20 cells) + mechanical cell identity + intercellular signaling
This means:
- More repos to integrate (pharynx model, intestinal oscillator, neuropeptide layer)
- More configuration knobs (which tissues enabled, which c302 level, which backend)
- More validation targets (Tier 1, 2, 3 across multiple tissues)
- More contributors touching different subsystems simultaneously
- More compute requirements (longer simulations, more particles, more neurons)
The current meta-repo architecture cannot support this growth.
Deliverables¶
docker-compose.yml— orchestration of all simulation containers (quick-test, simulation, validate, viewer, shell services)Dockerfile(multi-stage) — per-subsystem container definitions (base, neural, body, validation, full, viewer stages)versions.lock— pinned dependency versions (exact commit hashes) across all subsystemsopenworm.yml— unified declarative configuration file for simulation parametersmaster_openworm.py(enhanced) — orchestrator implementing all 5 pipeline steps driven by config.github/workflows/integration.yml— CI/CD pipeline with build, smoke test, and validation gatesscripts/quick-test.sh— contributor smoke test[TO BE CREATED]- Starter Jupyter notebooks (4) — orientation and exploration notebooks for newcomers
[TO BE CREATED]
Decision¶
1. Simulation Configuration System (openworm.yml)¶
Replace hardcoded defaults in master_openworm.py with a declarative YAML configuration file that specifies exactly what to simulate.
# openworm.yml — Simulation Configuration
# This file lives in the OpenWorm meta-repo root.
# Contributors copy and modify for their experiments.
version: "0.10.0"
# === Neural Subsystem ([DD001](DD001_Neural_Circuit_Architecture.md), [DD005](DD005_Cell_Type_Differentiation_Strategy.md), [DD006](DD006_Neuropeptidergic_Connectome_Integration.md)) ===
neural:
enabled: true
framework: c302
level: C1 # A, B, C, C1, C2, D
differentiated: false # Phase 1: CeNGEN cell-type specialization ([DD005](DD005_Cell_Type_Differentiation_Strategy.md))
neuropeptides: false # Phase 2: peptidergic modulation ([DD006](DD006_Neuropeptidergic_Connectome_Integration.md))
connectome_dataset: "Cook2019" # Cook2019, Witvliet2021, Varshney2011
data_reader: "UpdatedSpreadsheetDataReader2"
reference: "FW" # FW (forward crawl), BA (backward), TU (turning)
# === Body Physics ([DD003](DD003_Body_Physics_Architecture.md), [DD004](DD004_Mechanical_Cell_Identity.md)) ===
body:
enabled: true
engine: sibernetic
backend: opencl # opencl (production), pytorch (testing), taichi-metal (experimental), taichi-cuda (experimental)
configuration: "worm_crawl_half_resolution"
particle_count: 100000 # ~100K for standard, ~25K for quick
cell_identity: false # Phase 4: tagged particles ([DD004](DD004_Mechanical_Cell_Identity.md))
timestep: 0.00002 # seconds
# === Muscle Model ([DD002](DD002_Muscle_Model_Architecture.md)) ===
muscle:
enabled: true # Requires neural.enabled
calcium_coupling: true # Ca²⁺ → force pipeline
# === Pharynx ([DD007](DD007_Pharyngeal_System_Architecture.md)) — Phase 3 ===
pharynx:
enabled: false
pumping_frequency_target: 3.5 # Hz
# === Intestine ([DD009](DD009_Intestinal_Oscillator_Model.md)) — Phase 3 ===
intestine:
enabled: false
oscillator_period_target: 50.0 # seconds
# === Simulation Parameters ===
simulation:
duration: 15.0 # milliseconds
dt_neuron: 0.05 # ms (NEURON timestep)
dt_coupling: 0.005 # ms (neural↔body coupling interval)
output_interval: 100 # steps between output frames
# === Validation ([DD010](DD010_Validation_Framework.md)) ===
validation:
run_after_simulation: false # Set true for CI
tier1_electrophysiology: false # Single-cell validation
tier2_functional_connectivity: false # Circuit-level (requires 60s sim)
tier3_behavioral: false # Movement kinematics (requires ~5s sim)
# === Output ===
output:
directory: "./output"
video: true
plots: true
wcon: true # WCON movement file
raw_data: false # Full simulation state dumps
# === Visualization ([DD014](DD014_Dynamic_Visualization_Architecture.md)) ===
visualization:
enabled: true # Export OME-Zarr for viewer
export_format: "zarr" # "zarr" (OME-Zarr, recommended) or "legacy" (position_buffer.txt)
surface_reconstruction: true # Marching cubes → smooth body surface mesh
export_interval: 10 # Timesteps between Zarr frames (every 10th output frame)
viewer:
enabled: false # Launch Trame viewer after simulation
port: 8501 # Viewer port
backend: "trame" # "trame" (Phase 1) or "threejs" (Phase 2+)
default_layers: # Layers visible on startup
- body_surface
- muscles
Why this matters:
- Contributors can toggle subsystems on/off to test specific changes
- CI can run different configurations (quick smoke test vs. full validation)
- New subsystems (pharynx, intestine) plug in by adding a config section
- The configuration file is self-documenting (comments explain every option)
- Experiment reproducibility: commit the config file alongside results
2. Multi-Stage Docker Build (Layered Images)¶
Replace the monolithic Dockerfile with a multi-stage build that separates concerns:
# === Stage 0: Base Environment ===
# System packages, Python, NEURON, build tools
# Rebuilt rarely (only when system deps change)
FROM ubuntu:24.04 AS base
# ... system packages, Python 3, pip, virtualenv ...
RUN pip install neuron==8.2.6
# === Stage 1: Subsystem — c302 (Neural Circuit) ===
FROM base AS neural
ARG C302_REF=ow-0.10.0
RUN git clone --branch $C302_REF --depth 1 \
https://github.com/openworm/c302.git /opt/openworm/c302
RUN pip install -e /opt/openworm/c302
# === Stage 2: Subsystem — Sibernetic (Body Physics) ===
FROM base AS body
ARG SIBERNETIC_REF=ow-0.10.0
RUN git clone --branch $SIBERNETIC_REF --depth 1 \
https://github.com/openworm/sibernetic.git /opt/openworm/sibernetic
# OpenCL SDK + build
RUN cd /opt/openworm/sibernetic && mkdir build && cd build && \
cmake .. -DCMAKE_BUILD_TYPE=Release && make -j$(nproc)
# NOTE: Taichi/PyTorch backends require additional dependencies:
# pip install taichi torch
# These should be installed conditionally based on body.backend config.
# See DD003 Backend Stabilization Roadmap for when Taichi will be Dockerfile-ready.
# === Stage 3: Subsystem — Validation Tools ([DD010](DD010_Validation_Framework.md)) ===
FROM base AS validation
RUN git clone --depth 1 \
https://github.com/openworm/open-worm-analysis-toolbox.git \
/opt/openworm/validation
RUN pip install -e /opt/openworm/validation
# === Stage 4: Integration (Full Stack) ===
FROM base AS full
COPY --from=neural /opt/openworm/c302 /opt/openworm/c302
COPY --from=body /opt/openworm/sibernetic /opt/openworm/sibernetic
COPY --from=validation /opt/openworm/validation /opt/openworm/validation
# Copy orchestration
COPY master_openworm.py /opt/openworm/
COPY openworm.yml /opt/openworm/default_config.yml
# === Stage 5: Viewer ([DD014](DD014_Dynamic_Visualization_Architecture.md) Dynamic Visualization) ===
FROM full AS viewer
ARG WORM3DVIEWER_REF=main
RUN git clone --branch $WORM3DVIEWER_REF --depth 1 \
https://github.com/openworm/Worm3DViewer.git /opt/openworm/viewer
RUN pip install trame trame-vtk trame-vuetify pyvista zarr ome-zarr
# Surface reconstruction + OME-Zarr export utilities
COPY viewer/ /opt/openworm/viewer/
EXPOSE 8501
Benefits:
- Build caching: Changing c302 code only rebuilds Stage 1 + Stage 4 (not Sibernetic)
- Contributor override:
docker build --build-arg C302_REF=my-feature-branch .swaps in a custom c302 - Modular images: Can run just c302 (Stage 1) for neural-only development
- Smaller rebuild time: ~5 minutes for a single-subsystem change vs. ~20 minutes for full rebuild
3. Docker Compose for Composable Execution¶
Add a docker-compose.yml that defines services for different use cases:
# docker-compose.yml
version: "3.8"
services:
# === Quick smoke test (CI, contributor sanity check) ===
quick-test:
build:
context: .
target: full
command: >
python3 /opt/openworm/master_openworm.py
--config /opt/openworm/default_config.yml
--duration 10
--no-video
volumes:
- ./output:/opt/openworm/output
# === Standard simulation (default 15ms) ===
simulation:
build:
context: .
target: full
command: >
python3 /opt/openworm/master_openworm.py
--config /opt/openworm/default_config.yml
volumes:
- ./output:/opt/openworm/output
deploy:
resources:
limits:
memory: 8G
# === Full validation suite (CI blocking check) ===
validate:
build:
context: .
target: full
command: >
python3 /opt/openworm/master_openworm.py
--config configs/validation_full.yml
volumes:
- ./output:/opt/openworm/output
deploy:
resources:
limits:
memory: 16G
# === Viewer — Dynamic visualization ([DD014](DD014_Dynamic_Visualization_Architecture.md)) ===
viewer:
build:
context: .
target: viewer # New Docker stage (see below)
command: >
python3 /opt/openworm/viewer/app.py
--data /opt/openworm/output/openworm.zarr
--port 8501
ports:
- "8501:8501"
volumes:
- ./output:/opt/openworm/output
depends_on:
simulation:
condition: service_completed_successfully
# === Neural-only development (no body physics) ===
neural-dev:
build:
context: .
target: neural
command: >
python3 -c "from c302 import generate; generate('C1', 'FW')"
volumes:
- ./output:/opt/openworm/output
# === Interactive shell (contributor debugging) ===
shell:
build:
context: .
target: full
command: /bin/bash
stdin_open: true
tty: true
volumes:
- ./output:/opt/openworm/output
- .:/opt/openworm/workspace
Usage for contributors:
# Quick sanity check (2 minutes)
docker compose run quick-test
# Standard simulation
docker compose run simulation
# Full validation (for PRs to main)
docker compose run validate
# Interactive debugging
docker compose run shell
# Test with your branch of c302
docker compose build --build-arg C302_REF=my-feature-branch simulation
docker compose run simulation
4. Dependency Pinning (versions.lock)¶
Replace branch-name dependencies with a lockfile that pins exact commits:
# versions.lock — Pinned dependency versions
# Updated by the Integration Maintainer for each release.
# Contributors should NOT modify this file.
c302:
repo: "https://github.com/openworm/c302.git"
commit: "a1b2c3d4e5f6" # Exact commit hash
tag: "ow-0.10.0"
pypi_version: null # If published to PyPI
sibernetic:
repo: "https://github.com/openworm/sibernetic.git"
commit: "f6e5d4c3b2a1"
tag: "ow-0.10.0"
connectome_toolbox:
repo: "https://github.com/openworm/ConnectomeToolbox.git"
commit: "1a2b3c4d5e6f"
pypi_version: "0.2.7" # Also pinned via pip
neuron:
pypi_version: "8.2.6"
open_worm_analysis_toolbox:
repo: "https://github.com/openworm/open-worm-analysis-toolbox.git"
commit: "6f5e4d3c2b1a" # [DD021](DD021_Movement_Analysis_Toolbox_and_WCON_Policy.md) revival — pin after Python 3.12 update
tracker_commons:
repo: "https://github.com/openworm/tracker-commons.git"
commit: "a1b2c3d4e5f6" # [DD021](DD021_Movement_Analysis_Toolbox_and_WCON_Policy.md) — WCON 1.0 spec pin
wcon_version: "1.0"
owmeta:
repo: "https://github.com/openworm/owmeta.git"
commit: "deadbeef1234"
# System dependencies (Dockerfile apt-get)
system:
ubuntu: "24.04"
python: "3.12"
java: "8"
# External SDKs (with checksum for integrity)
opencl_sdk:
url: "https://github.com/openworm/sibernetic/releases/download/v1.0/AMD-APP-SDK-3.0.tar.bz2"
sha256: "abc123..." # Verify download integrity
Build script reads versions.lock:
# build.sh (enhanced)
C302_COMMIT=$(python3 -c "import yaml; print(yaml.safe_load(open('versions.lock'))['c302']['commit'])")
docker build \
--build-arg C302_REF=$C302_COMMIT \
--build-arg SIBERNETIC_REF=$(get_version sibernetic) \
-t openworm/openworm:$(cat VERSION) .
5. Enhanced master_openworm.py (Implement All 5 Steps)¶
The orchestrator must implement the full pipeline, driven by openworm.yml:
Step 1: Load configuration (openworm.yml)
Step 2: Initialize subsystems based on config
- If neural.enabled: generate c302 network at specified level
- If body.enabled: initialize Sibernetic with specified backend
- If pharynx.enabled: initialize pharyngeal circuit
- If intestine.enabled: initialize intestinal oscillator
Step 3: Run coupled simulation
- Time-step loop with configurable coupling intervals
- Each enabled subsystem advances one step
- Data exchange at coupling boundaries (Ca²⁺ → forces, etc.)
Step 4: Generate outputs
- Plots (membrane potentials, calcium, movement)
- WCON trajectory file
- Video (if enabled — fix the memory leak first)
Step 4b: Export OME-Zarr ([DD014](DD014_Dynamic_Visualization_Architecture.md), if visualization.enabled)
- Collect all subsystem outputs into openworm.zarr
- body/positions, body/types, body/cell_ids ([DD003](DD003_Body_Physics_Architecture.md), [DD004](DD004_Mechanical_Cell_Identity.md))
- neural/voltage, neural/calcium, neural/positions ([DD001](DD001_Neural_Circuit_Architecture.md))
- muscle/activation, muscle/calcium ([DD002](DD002_Muscle_Model_Architecture.md))
- pharynx/pumping_state ([DD007](DD007_Pharyngeal_System_Architecture.md), if pharynx.enabled)
- intestine/calcium, intestine/defecation_events ([DD009](DD009_Intestinal_Oscillator_Model.md), if intestine.enabled)
- neuropeptides/concentrations ([DD006](DD006_Neuropeptidergic_Connectome_Integration.md), if neural.neuropeptides)
- validation/overlay ([DD010](DD010_Validation_Framework.md), if validation.run_after_simulation)
- geometry/ (cell metadata, VirtualWorm meshes)
- Run surface reconstruction (marching cubes) if visualization.surface_reconstruction
Step 5: Run validation (if enabled)
- Tier 1: Single-cell electrophysiology checks
- Tier 2: Functional connectivity vs. Randi 2023
- Tier 3: Behavioral kinematics vs. Schafer lab
- Generate pass/fail report
- Exit with non-zero code if blocking tiers fail
Critical fix needed: The video generation pipeline (xvfb + tmux + ffmpeg screen capture) must be replaced. Options:
- Headless rendering via OSMesa or EGL (no X server needed)
- Post-hoc visualization from saved particle positions (decouple recording from simulation)
- Skip video in CI (validation doesn't need video, only data)
6. CI/CD Pipeline (Automated Quality Gates)¶
# .github/workflows/integration.yml
name: Integration Test Suite
on:
pull_request:
branches: [main, dev*]
push:
branches: [main]
jobs:
# === Gate 1: Build (does it compile?) ===
build:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker compose build simulation
# === Gate 2: Smoke test (does it run?) ===
smoke-test:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Run 10ms simulation (no video)
run: docker compose run quick-test
- name: Check outputs exist
run: |
test -f output/*.png && echo "Plots: OK"
test -f output/*.wcon && echo "WCON: OK"
# === Gate 3: Tier 2 validation (circuit-level, BLOCKING) ===
tier2-validation:
needs: smoke-test
runs-on: ubuntu-latest
timeout-minutes: 60
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- name: Run functional connectivity validation
run: docker compose run validate
- name: Check pass/fail
run: python3 scripts/check_ci_results.py output/validation_report.json
# === Gate 4: Tier 3 validation (behavioral, BLOCKING for main) ===
tier3-validation:
needs: smoke-test
runs-on: ubuntu-latest
timeout-minutes: 120
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Run behavioral validation (5s sim)
run: >
docker compose run -e DURATION=5000 validate
- name: Upload validation report
uses: actions/upload-artifact@v4
with:
name: validation-report
path: output/validation_report.json
# NOTE: Once Taichi graduates to Production (see DD003 Backend Stabilization Roadmap),
# CI should run smoke tests on multiple backends (at minimum OpenCL + one Python backend)
# to catch backend-specific regressions.
7. Contributor Development Workflow¶
For contributors working on a specific subsystem:¶
# 1. Fork the subsystem repo (e.g., c302)
gh repo fork openworm/c302
# 2. Clone the meta-repo (for integration testing)
git clone https://github.com/openworm/OpenWorm.git
cd OpenWorm
# 3. Build with your branch of c302
docker compose build --build-arg C302_REF=my-feature-branch simulation
# 4. Run quick test
docker compose run quick-test
# 5. Check results
ls output/ # PNGs, WCON files
# 6. Run validation before submitting PR
docker compose run validate
# 7. If validation passes, submit PR to c302 repo
# CI on the meta-repo will automatically test the integration
For contributors adding a new subsystem (e.g., DD007 pharynx):¶
# 1. Create new repo (L4 maintainer action)
gh repo create openworm/pharynx-model --public
# 2. Add to versions.lock
# pharynx:
# repo: "https://github.com/openworm/pharynx-model.git"
# commit: "initial"
# 3. Add Docker stage to Dockerfile
# FROM base AS pharynx
# RUN git clone ... /opt/openworm/pharynx
# 4. Add config section to openworm.yml
# pharynx:
# enabled: false # Off by default until validated
# 5. Add coupling code to master_openworm.py
# if config['pharynx']['enabled']:
# pharynx.step(dt)
# 6. Add validation targets
# validation:
# pharynx_pumping: true # 3-4 Hz check
# 7. Submit PR to meta-repo with all of the above
8. Pre-Built Images on Docker Hub¶
For users who just want to run the simulation without building:
# Pull and run (no build required)
docker pull openworm/openworm:0.10.0
docker run -v $(pwd)/output:/opt/openworm/output openworm/openworm:0.10.0
# Or with docker compose
docker compose pull simulation
docker compose run simulation
Automated publishing: GitHub Actions builds and pushes tagged images to Docker Hub on every release.
9. JupyterLab Interface (Issue #347)¶
Add an optional JupyterLab service for interactive exploration:
# docker-compose.yml (additional service)
jupyter:
build:
context: .
target: full
command: >
jupyter lab --ip=0.0.0.0 --port=8888 --no-browser
--NotebookApp.token=''
--notebook-dir=/opt/openworm/notebooks
ports:
- "8888:8888"
volumes:
- ./output:/opt/openworm/output
- ./notebooks:/opt/openworm/notebooks
Include starter notebooks:
01_explore_connectome.ipynb— Load and visualize the connectome02_run_c302_network.ipynb— Generate and simulate a neural circuit03_analyze_output.ipynb— Plot simulation results04_validate_against_data.ipynb— Run validation comparisons
This directly addresses newcomer onboarding (DD011 L0→L1 tasks) and makes orientation tasks executable in a browser.
Alternatives Considered¶
1. Monorepo (All Subsystems in One Repository)¶
Advantages: Single clone, atomic commits across subsystems, simple CI.
Rejected because:
- OpenWorm already has 109 repos with established histories
- Different subsystems have different maintainers and release cadences
- Monorepo migration would be massively disruptive
- The current multi-repo approach is standard for scientific projects
When to reconsider: Never. The multi-repo approach with a meta-repo integrator is the right pattern for this project.
2. Git Submodules¶
Advantages: Built-in Git feature, pins exact commits.
Rejected because:
- Submodules are notoriously confusing for contributors (
git clone --recursive, detached HEAD, update commands) - OpenWorm tried this before (the meta-repo once had submodules — they were removed)
- The
versions.lock+ build-arg approach gives the same pinning benefits without submodule pain
3. Nix / Guix for Reproducible Builds¶
Advantages: Perfectly reproducible, content-addressed, covers system deps.
Rejected because:
- Extremely steep learning curve (most contributors won't know Nix)
- Docker is already the standard in this project and the broader scientific computing community
- Nix inside Docker is possible but adds complexity without clear benefit for this project size
4. Kubernetes / Microservices (One Container Per Subsystem)¶
Advantages: Clean separation, independent scaling, true composability.
Rejected because:
- Massive operational overhead for a volunteer-run open source project
- The subsystems communicate via shared memory and files, not network APIs
- Latency between containers would harm the tight neural↔body coupling loop
- Nobody would maintain a Kubernetes cluster
5. Keep Current Approach (Single Dockerfile, Shell Scripts)¶
Rejected because:
- Cannot support adding new subsystems without growing a monolithic Dockerfile
- No contributor workflow for testing changes against the full stack
- No automated validation
- Memory leak and video pipeline issues remain unaddressed
- Single maintainer is a bus factor risk
How to Build & Test¶
Prerequisites¶
- Docker Engine 24+ and Docker Compose v2 (
docker compose— note: no hyphen) - Git
- 8 GB RAM minimum (16 GB recommended for full validation)
- 10 GB disk space for Docker images
- Optional: GPU with OpenCL support (for accelerated body physics)
Getting Started (Environment Setup)¶
DD013 defines the Docker infrastructure that all other DDs depend on. This is the canonical guide for setting up the entire OpenWorm simulation environment. Other DDs cross-reference this section for their Docker setup paths.
Clone the meta-repo:
git clone https://github.com/openworm/OpenWorm.git
cd OpenWorm
Path A — Docker (primary, recommended for all users):
# Build all subsystem images (neural, body, validation, viewer)
docker compose build
# Run a quick smoke test (2 minutes, verifies everything works)
docker compose run quick-test
# Run a standard simulation (15ms default)
docker compose run simulation
# Run full validation suite (for PRs to main)
docker compose run validate
# Launch the visualization viewer (after simulation completes)
docker compose up viewer
# Opens at http://localhost:8501
Building with a custom subsystem branch:
Contributors working on a specific subsystem (e.g., c302) can swap in their branch:
# Build with your fork's branch of c302
docker compose build --build-arg C302_REF=my-feature-branch simulation
# Test your changes against the full stack
docker compose run quick-test
Similarly for Sibernetic: --build-arg SIBERNETIC_REF=my-branch.
Pre-built images (no build required):
# Pull the latest release image from Docker Hub
docker pull openworm/openworm:0.10.0
docker run -v $(pwd)/output:/opt/openworm/output openworm/openworm:0.10.0
# Or with docker compose
docker compose pull simulation
docker compose run simulation
Path B — Native (individual subsystems only):
DD013 defines the Docker orchestration layer. Running the full integrated simulation natively is not supported — Docker is the integration surface. However, individual subsystems can be run natively per their own DDs:
| Subsystem | DD | Native Setup |
|---|---|---|
| Neural circuit (c302) | DD001 | pip install -e c302; pip install pyneuroml neuron |
| Body physics (Sibernetic) | DD003 | CMake build with OpenCL SDK |
| Validation tools | DD010, DD021 | pip install -e open-worm-analysis-toolbox |
| Visualization viewer | DD014 | pip install trame pyvista zarr |
See each DD's own Getting Started section for native setup details.
Interactive shell (debugging):
docker compose run shell
# Drops into a bash shell inside the full simulation container
# All subsystems are available at /opt/openworm/
Step-by-step¶
# Step 1: Build the Docker images
docker compose build
# Expected: all stages build successfully (base, neural, body, validation, full, viewer)
# Step 2: Run quick smoke test
docker compose run quick-test
# Expected: 10ms simulation completes, output/ contains PNGs and WCON file
# Step 3: Verify outputs exist
ls output/
# Expected: *.png (plots), *.wcon (trajectory), openworm.zarr/ (OME-Zarr data)
# Step 4: Run validation (for PRs)
docker compose run validate
# Expected: validation_report.json in output/ with tier pass/fail results
# Step 5: Launch viewer
docker compose up viewer
# Expected: web app at http://localhost:8501 showing animated worm
# Step 6: Test with custom configuration
cp openworm.yml my_experiment.yml
# Edit my_experiment.yml (e.g., change duration, enable/disable subsystems)
docker compose run -e CONFIG=/opt/openworm/my_experiment.yml simulation
Green Light Criteria¶
| Check | Pass Condition |
|---|---|
| Docker build | docker compose build completes without errors |
| Smoke test | docker compose run quick-test exits 0, output files present |
| Simulation | docker compose run simulation produces PNGs, WCON, and OME-Zarr output |
| Validation | docker compose run validate produces validation_report.json |
| Viewer | docker compose up viewer serves at localhost:8501 |
| Custom config | Modified openworm.yml is respected by the simulation |
Quality Criteria¶
For the Simulation Stack Itself¶
-
Build succeeds in CI on every push to main. Zero tolerance for broken builds.
-
Quick test completes in <5 minutes. This is the contributor feedback loop — if it takes longer, people won't run it.
-
Full validation suite completes in <2 hours. This runs on PRs to main. Must be fast enough to not block contributor workflow.
-
Pre-built Docker images published for every tagged release. Users should never need to build from source unless developing.
-
Configuration file is the single source of truth. No simulation parameters hardcoded in Python scripts, Dockerfiles, or shell scripts.
-
Every subsystem can be disabled independently. A contributor working on c302 should be able to run neural-only simulations without building Sibernetic.
-
versions.lockis updated atomically with releases. When we release 0.10.0, all component commits are pinned together.
For Contributors¶
-
A new contributor can go from
git cloneto running simulation in <30 minutes (including Docker image pull, not build). -
Testing a change to one subsystem requires rebuilding only that subsystem's Docker stage (~5 minutes, not 20).
-
Validation results are automatically reported on PRs. Contributors see pass/fail before human review.
Boundaries (Out of Scope)¶
This Design Document Does NOT Cover:¶
-
Cloud execution. Running simulations on AWS/GCP/Azure is out of scope. The stack runs locally in Docker. Cloud deployment can be a future DD.
-
Real-time visualization. Geppetto (the web-based viewer) is dormant and not part of this architecture. Post-hoc visualization via Jupyter notebooks is in scope.
-
Multi-node / HPC distribution. The simulation runs on a single machine. Distributing across nodes (MPI) is future work.
-
Specific subsystem implementations. This DD covers how subsystems plug together, not what they compute internally (that's DD001-DD009).
-
AI agent deployment. N2-Whisperer/Mind-of-a-Worm/Mad-Worm-Scientist are separate infrastructure (see AI Agents for Community Scaling).
Ownership and Maintenance¶
Integration Is a Shared Responsibility¶
Integration is not solely the Integration Maintainer's job. The INTEGRATION_AUDIT.md (produced alongside this DD) identified that every Design Document was originally written in isolation — specifying what each subsystem does but not how it composes with the rest of the organism.
The fix: every DD now has an Integration Contract section (inputs, outputs, config, Docker, integration test, coupling dependencies). This distributes integration responsibility:
| Role | Integration Responsibility |
|---|---|
| Integration Maintainer (L4) | Owns Docker build, CI pipeline, openworm.yml schema, versions.lock, master_openworm.py orchestrator |
| Subsystem Maintainer (L4) | Owns their DD's Integration Contract. Ensures changes to their subsystem don't break downstream consumers. Updates consuming DDs' input specs when outputs change. |
| Committer (L3) | When reviewing PRs, checks the DD's Integration Contract section. If a PR changes a coupling interface, coordinates with consuming subsystem maintainers before merging. |
| Contributor (L2) | Runs docker compose run quick-test before submitting PRs. Includes integration test results in PR description. |
| Mind-of-a-Worm (AI) | Automatically identifies coupling interface changes, tags affected maintainers, verifies integration test evidence in PR description. |
| Mad-Worm-Scientist (AI) | Escalates integration CI failures on main as IMMEDIATE priority to founder. |
The through-line: The Integration Maintainer owns the infrastructure that makes integration possible. But every contributor, reviewer, and maintainer is responsible for keeping their piece integratable. Mind-of-a-Worm automates what it can; human judgment handles the rest.
New Role: L4 Integration Maintainer¶
This Design Document introduces a new entry in the Subsystem Ownership Map (DD011):
| Subsystem | Design Documents | L4 Maintainer | Primary Repository |
|---|---|---|---|
| Integration Stack | DD013 (this), DD010 | TBD — Critical hire | openworm/OpenWorm |
The Integration Maintainer is responsible for:
| Responsibility | Frequency | Effort |
|---|---|---|
| Merge PRs to meta-repo | As needed | 1-2 hrs/week |
Update versions.lock for releases |
Monthly | 2-4 hrs/month |
| Maintain Dockerfile and docker-compose | As needed | 1-2 hrs/month |
| Maintain CI/CD pipeline | As needed | 1-2 hrs/month |
| Review subsystem integration PRs | As needed | 2-3 hrs/week |
| Triage integration issues | Weekly | 1 hr/week |
| Coordinate with subsystem L4 maintainers | Bi-weekly | 30 min |
| Update getting-started documentation | Per release | 2-4 hrs/release |
Total estimated effort: 5-10 hrs/week.
Who should fill this role:
- Currently the Neural Circuit L4 Maintainer is doing this de facto but it's not formalized or sustainable alongside their Neural Circuit role
- Ideal candidate: Someone with strong DevOps/Docker experience who also understands the science
- Alternative: An L3 contributor who can be mentored into this role
- Mind-of-a-Worm AI can assist with routine tasks (dependency updates, CI triage) but cannot own architectural decisions
Founder involvement: Approve L4 appointment, review major architectural changes (per DD011). This role should reduce founder time, not increase it.
Mind-of-a-Worm Support for Integration¶
Mind-of-a-Worm (AI agent) can automate routine integration tasks:
-
Dependency staleness alerts: Weekly check if any pinned commit in
versions.lockis >30 days behind the subsystem repo's main branch. Post alert to#development. -
CI failure triage: When CI fails, Mind-of-a-Worm reads the logs, identifies which subsystem broke, and tags the relevant L4 maintainer.
-
PR integration checklist: When a PR modifies
openworm.yml,versions.lock, orDockerfile, Mind-of-a-Worm verifies:- Config schema is valid
- All referenced repos/commits exist
- No subsystem accidentally disabled
- Version numbers are consistent
-
Onboarding verification: For L0→L1 Task B1 ("Install and run Docker simulation"), Mind-of-a-Worm can verify the output screenshot includes the correct version string.
Implementation Roadmap¶
For the granular task breakdown of DD013 implementation, see the DD013 Draft Issues (42 issues organized into Phases A–D, Infrastructure, and Backend Stabilization). For project-wide phasing and timeline, see the DD Phase Roadmap — DD013 is assigned to Phase A: Infrastructure Bootstrap (Weeks 1–4).
The Contributor → Simulation Feedback Loop¶
This is the critical path that makes the whole system work:
Contributor makes a change
│
▼
Pushes to their fork of a subsystem repo (e.g., c302)
│
▼
Runs locally: docker compose build --build-arg C302_REF=my-branch simulation
docker compose run quick-test (~2 min)
docker compose run validate (~30 min)
│
▼
Opens PR to subsystem repo
│
▼
Subsystem CI runs (unit tests for that repo)
│
▼
Integration CI triggered (runs full stack with PR branch)
├── Build: Does it compile with the rest of the stack?
├── Smoke test: Does it produce output?
├── Tier 2: Does functional connectivity hold?
└── Tier 3: Does movement still look right?
│
▼
Mind-of-a-Worm pre-review:
├── Design Document compliance check
├── Code style and test coverage
└── Validation results summary
│
▼
Human review (L3/L4)
│
▼
Merge → versions.lock updated → next release includes change
│
▼
Docker Hub image published
│
▼
Next newcomer who runs the Docker image sees the improvement
This is the through-line: Every contributor's work flows through a path that ends with the next newcomer experiencing a better simulation. The Docker image is the product. The configuration system is the interface. The validation framework is the quality gate. The meta-repo is the integration point.
Open Questions (Require Founder Input)¶
-
Who is the L4 Integration Maintainer? The Neural Circuit L4 Maintainer is the de facto integration maintainer but this should be formalized and ideally shared with someone else to reduce bus factor.
-
GPU support priority: Should we invest in fixing Docker GPU passthrough (issue #320) now, or wait for Phase 1 to be further along? GPU would make longer simulations practical.
-
MyBinder vs. Google Colab: For zero-install demos, MyBinder is fully open but resource-limited. Google Colab has GPU but requires Google account. Which aligns better with open science values?
-
OpenCL SDK hosting: The AMD SDK is currently downloaded from SourceForge at build time. Should we host it in the OpenWorm org (GitHub Releases on the sibernetic repo) for reliability?
-
Release cadence target: Current cadence is roughly quarterly. Should we aim for monthly releases once the new stack is in place?
Existing Code Resources¶
sibernetic_config_gen (openworm/sibernetic_config_gen, 2016, dormant):
Generates starting particle positions and .ini config files for Sibernetic. Contains particle placement algorithms for different body resolutions. Reusable for DD013's openworm.yml → Sibernetic .ini translation layer. Estimated time savings: 10-20 hours.
sibernetic_NEURON (openworm/sibernetic_NEURON, 2016, dormant):
Predecessor to sibernetic_c302.py — contains Sibernetic-NEURON interface code. Review for patterns applicable to DD019's bidirectional coupling.
skeletonExtraction (openworm/skeletonExtraction, 2016, dormant): Extracts 49-point skeleton (centerline) from Sibernetic particle output, exports to COLLADA. The skeleton extraction algorithm is directly needed for DD013's SPH → WCON export pipeline and DD021's analysis toolbox input. Estimated time savings: 15-25 hours.
References¶
- Docker multi-stage builds. https://docs.docker.com/build/building/multi-stage/
- Docker Compose specification. https://docs.docker.com/compose/compose-file/
- GitHub Actions for Docker. https://docs.docker.com/build/ci/github-actions/
- MyBinder.org. https://mybinder.org/ — Zero-install reproducible environments
- Sarma et al. (2016). "Unit testing, model validation, and biological simulation." F1000Research 5:1946.
- OpenWorm/OpenWorm repository. https://github.com/openworm/OpenWorm
Migration Path¶
From v0.9.x to v0.10.0 (This DD)¶
- v0.9.7 remains available. The current Dockerfile and scripts are preserved in the
legacy-0.9.xbranch. - v0.10.0 introduces the new architecture (
openworm.yml, multi-stage Docker, docker-compose,versions.lock). - Backward compatibility:
run.shcontinues to work but prints a deprecation notice pointing todocker compose run simulation. - No behavioral change: The default
openworm.ymlproduces the same simulation output as v0.9.7 (c302 Level C2, Sibernetic half-res, 15ms). - Phased introduction: New subsystems (pharynx, intestine, neuropeptides) are added as
enabled: falseconfig options. Contributors opt in.
Integration Contract¶
Inputs / Outputs¶
The simulation stack is the integration layer — it consumes and routes outputs from all science DDs:
| Direction | DD | Data | Format |
|---|---|---|---|
| Consumes | DD001 | Neural state | OME-Zarr /neural/ |
| Consumes | DD002 | Muscle forces | OME-Zarr /muscle/ |
| Consumes | DD003 | Body geometry | OME-Zarr /physics/ |
| Produces | All | Unified simulation state | OME-Zarr /simulation/ |
Repository & Packaging¶
- Primary repository:
openworm/OpenWorm - Docker multi-stage build: orchestrator layer
versions.lockkey:openworm
Configuration¶
openworm.ymlroot section:simulation:- Key parameters:
timestep,duration,output_format,subsystems[]
How to Test (Contributor Workflow)¶
docker compose run quick-test— verifies all containers start and communicatedocker compose run validate— runs DD010 Tier 2 correlation check
Coupling Dependencies¶
- Upstream: DD001, DD002, DD003, DD005, DD006, DD007, DD009 (all science subsystems)
- Downstream: DD014 (visualization), DD010 (validation)
- Approved by: Pending (requires founder + Integration Maintainer appointment)
- Implementation Status: Proposed
-
Next Actions:
-
Appoint or recruit L4 Integration Maintainer
- Begin Phase A (config system + multi-stage Docker)
- Fix the video pipeline memory leak (critical for any serious use)
- Set up CI with docker-compose-based test suite