This guide gets the Pioreactor monorepo running on a development laptop:
- Flask web API:
make web-dev - React frontend:
make frontend-dev - Huey task consumer:
make huey-dev - Local CLI:
pio
The development flow is POSIX-shell based. On macOS, use Terminal. On Windows, use WSL2 with Ubuntu rather than PowerShell or native cmd.exe.
Install Homebrew if needed, then install the basic runtime tools:
brew install python@3.13 node@20 direnv make mosquittoMake sure python3.13, node, npm, make, and direnv are available:
python3.13 --version
node --version
npm --version
make --version
direnv --versionUse WSL2:
wsl --install -d UbuntuOpen Ubuntu, then install the base tools:
sudo apt update
sudo apt install -y build-essential curl git make direnv mosquittoInstall Python 3.13 and Node 20. The most reliable cross-distro option is pyenv for Python and nvm for Node:
curl https://pyenv.run | bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bashRestart the Ubuntu shell, then:
pyenv install 3.13.0
pyenv global 3.13.0
nvm install 20
nvm use 20Confirm:
python3.13 --version
node --version
npm --versionKeep the repo inside the Linux filesystem, for example ~/code/pioreactor, not under /mnt/c/.... File watching and virtualenv behavior are much better there.
git clone https://github.com/Pioreactor/pioreactor.git
cd pioreactorIf you already have the repo, start from its root directory.
The app expects a Pioreactor data root with config, storage, plugins, and export directories. For local development, keep that under the repo as .pioreactor.
mkdir -p .pioreactor/storage .pioreactor/cache .pioreactor/plugins .pioreactor/experiment_profiles .pioreactor/exportable_datasets plugins_dev
cp -n config.dev.ini .pioreactor/config.ini
touch .pioreactor/unit_config.iniDo not commit .envrc, .pioreactor/, plugins_dev/, or generated local state.
Create a local .envrc:
export TESTING=1
export HOSTNAME=localhost
export ACTIVE=1
export DOT_PIOREACTOR="$PWD/.pioreactor"
export GLOBAL_CONFIG="$DOT_PIOREACTOR/config.ini"
export RUN_PIOREACTOR="$DOT_PIOREACTOR"
export PLUGINS_DEV="$PWD/plugins_dev"
export PIO_EXECUTABLE="$PWD/.venv/bin/pio"
export PIOS_EXECUTABLE="$PWD/.venv/bin/pios"
PATH_add "$PWD/.venv/bin"
export HARDWARE=1.1
export FIRMWARE=1.1
export MODEL_NAME=pioreactor_40ml
export MODEL_VERSION=1.5
export BLINKA_FORCECHIP=BCM2XXX
export BLINKA_FORCEBOARD=RASPBERRY_PI_4BAllow it:
direnv allowCheck that the required variables are loaded:
make check-envIf you do not use direnv, export the same variables manually in every shell before running make, pio, or pios. Replace the PATH_add line with export PATH="$PWD/.venv/bin:$PATH".
Install Python dependencies and the editable pio / pios commands:
make installInstall frontend dependencies:
make frontend-installConfirm the CLI is available:
command -v pio
pio versionIf command -v pio prints nothing, reload the shell or run:
direnv reloadYou can always run the CLI directly as:
.venv/bin/pio versionMany pages still load without MQTT, but live job state, charts, and browser MQTT subscriptions need a local broker. Use this small dev config:
mkdir -p scratch
cat > scratch/mosquitto-dev.conf <<'EOF'
listener 1883 127.0.0.1
allow_anonymous true
listener 9001 127.0.0.1
protocol websockets
allow_anonymous true
EOFStart Mosquitto in its own terminal:
mosquitto -c scratch/mosquitto-dev.confLeave it running while using the web UI.
First ask the Makefile what is already running:
make dev-statusStart only the services listed under Need to start. In separate terminals:
make huey-devmake web-devmake frontend-devThe web API listens on http://127.0.0.1:4999. The React dev server listens on http://localhost:3000 and proxies API requests to http://localhost:4999.
Open:
http://localhost:3000
Run these checks from the repo root:
make dev-status
pio version
pio workers
curl -fsS http://127.0.0.1:4999/unit_api/healthThe pio command is created by make install when it installs core/ in editable mode. Run:
PYTHON=python3.13 make install
direnv reload
command -v pioOr use .venv/bin/pio directly.
Make sure the Flask API is running:
make dev-statusIf Flask web API is missing, start:
make web-dev