⚠ Under heavy construction

As of July 11, 2026, Sorter V2 is not yet in a position to be built.

The documentation that exists is incomplete. Any given page may be accurate, inaccurate, present only as an example, or badly out of date. We do not yet recommend that anyone attempt to build Sorter.

For the most live updates on our progress, join our Discord ↗.

Installation — Linux

Install on Linux (generic)

Installation

How to take a fresh Linux box from clean install to a running SorterOS UI in your browser. One script, two flags, then the in-app Setup Wizard takes over.

Supported platforms

The installer is written against a freshly installed Debian 12 or Ubuntu 24.04 system (amd64 or aarch64). It also works on Raspberry Pi OS Bookworm on a Pi 5, which is the canonical target.

Prerequisites

  • a sudo-capable user account
  • a working internet connection
  • ~3 GB free disk (Python interpreter, node_modules, model artifacts)

The one-command install

git clone https://github.com/basicallysource/sorter-v2.git
cd sorter-v2/software
./install.sh

That's it. The installer is idempotent — re-running it on a partially-installed machine just confirms the steps it can skip.

What install.sh actually does, in order:

  1. apt install the system packages: git, curl, build-essential, libgl1, libglib2.0-0, lsof, v4l-utils. libgl1 is what OpenCV needs at import time.
  2. Install a udev rule for Raspberry Pi Pico boards (/etc/udev/rules.d/99-sorter-pico.rules), so Pico USB access belongs to the plugdev group plus the active desktop seat user. The installer adds your user to plugdev; a headless or SSH session needs a logout and login before that takes effect.
  3. Install uv, the Python toolchain, if it is not already on the box. uv then fetches the exact Python version the project pins, so you do not need apt python3.
  4. Install Node.js 20.x and pnpm via NodeSource. pnpm is what the dev runner invokes, so npm and yarn do not substitute.
  5. Write software/.env if there is not one already.
  6. Copy machine.example.toml to software/machine.toml if there is not one already. That copy is the machine's own config, and settings you save in the UI are written to it. The example itself is never used directly, so a setting you save never lands in a file git tracks.
  7. uv sync in software/sorter/backend/. This is the slow step on a first install, because uv downloads the Python interpreter and resolves the backend dependencies, OpenCV and ONNX Runtime among them.
  8. pnpm install --frozen-lockfile in software/sorter/frontend/, which resolves the UI toolchain.

An existing .env or machine.toml is left alone, which is what makes a re-run safe.

Verify the install

When the installer finishes you can start the dev runner:

./dev.sh

./dev.sh starts the Python backend on :8000 and the Vite dev server on :5173, prefixes both log streams, and restarts either one if it crashes. Stop with Ctrl-C.

Then open http://localhost:5173/ (or http://<machine-ip>:5173/ from another device on the same network). You should see the SorterOS UI.

If the UI does not come up, see SorterOS troubleshooting.

The finished result

The SorterOS UI open in a browser, with nothing set up on the machine yet.

Screenshot of the SorterOS UI as it first loads on a generic Linux install, before the setup wizard has been run.

Next

Flash the control board before you open the setup wizard. The wizard only lists boards that already answer on USB serial, so a board with no firmware on it does not appear and the wizard says No MCU buses found. Software setup step 2 has the route.

Then First setup in the UI takes the setup wizard step by step.

Installer flags

./install.sh --help
./install.sh                 # default — install everything in dev mode
./install.sh --as-service    # also build the UI and run the Sorter as a systemd service
./install.sh --skip-apt      # skip the apt step (useful when packages are already installed)

Running as a systemd service

For an "appliance" install on the Pi 5 that should boot straight into a running SorterOS without anyone touching ./dev.sh:

./install.sh --as-service

In addition to all the steps above, this also:

  • runs pnpm build, which writes the UI as static files to software/sorter/frontend/build/;
  • substitutes the actual user, paths, and binary locations into the unit templates under software/systemd/;
  • writes two units into /etc/systemd/system/: sorter-backend.service and its -dev variant;
  • runs systemctl daemon-reload, then systemctl enable --now sorter-backend-dev.service, so it starts immediately and on every subsequent boot.

It is the -dev unit that gets enabled. The two differ only in how quickly systemd restarts them; enable sorter-backend.service instead if you prefer.

The backend's supervisor serves the UI on port 80, so a service install answers at http://<machine name>/ with no port on the end. It serves the build, so there is no Node process running on the machine, and the page still loads while the backend itself restarts. The :5173 address is the dev runner's, and only applies when you start ./dev.sh by hand. After changing UI code, run pnpm build in software/sorter/frontend/ again; the next page load picks it up.

View the logs with:

sudo journalctl -u sorter-backend-dev -f

Verifying the installer in Docker

The whole install path is reproducibly tested against a fresh Debian 12 container so we catch regressions before they hit a real machine. From the repo root:

software/scripts/test_install_in_docker.sh

This script:

  1. builds a minimal debian:12-slim image whose only pre-installed packages are sudo, curl, ca-certificates and git, so everything else has to come from install.sh itself;
  2. copies the working tree into the container, strips any host-side dev state (.env, .venv, node_modules), and runs ./install.sh;
  3. smoke-tests the backend by importing the trickiest Python dependencies (fastapi, cv2, onnxruntime, uvicorn, numpy) inside the freshly built uv environment;
  4. runs pnpm exec vite --version to confirm the UI toolchain is callable;
  5. runs systemd-analyze verify against the unit files to catch syntax regressions.

What the Docker test deliberately does not cover: USB serial discovery of Pico boards, camera enumeration, Hailo / RKNN runtimes, anything else that needs physical hardware. Those are exercised on real devices, not in CI.