How OpenBenchML Works

A visual walkthrough of every workflow, every layer, every moving part — from the moment you paste Python code to the moment a leaderboard row lights up in someone else's browser.

v4.2.0 FastAPI + SQLAlchemy + Jinja2 WebSocket real-time Server-side Python kernel
🏗

Architecture at a glance

Three layers, each doing one job. Click any workflow below to see how data flows through them.

Browser
Jinja2-rendered HTML + vanilla JS + fetch(). xterm.js for the terminal. WebSocket client for live updates.
FastAPI server
Async route handlers, Pydantic validation, per-user kernel sessions, WebSocket broadcast, sandboxed shell executor.
Database + files
SQLAlchemy ORM → SQLite (dev) / Supabase Postgres (prod). Pickled models live on disk under uploads/.
🚀

What is OpenBenchML?

OpenBenchML is an open-source platform that turns Python ML code into benchmarked, ranked, shareable models — without you ever leaving the browser.

At its core, the platform is a FastAPI application backed by a relational database (SQLite in dev, Supabase Postgres in prod) and a Jinja2 template layer that renders server-side HTML. On top of that engine sit four major surfaces: a model upload + benchmark pipeline, a paste-and-pickle Convert page, a Colab-style Notebook with a real bash terminal, and a real-time WebSocket layer that pushes leaderboard updates to every open browser.

Every request flows through a middleware stack — GZip compression, CORS, request-timing, security headers — before reaching the route handler. Auth is cookie-based (JWT inside an httpOnly cookie), and most write endpoints are user-scoped: your models, your notebooks, your submissions. The codebase is intentionally readable: each route file in app/routes/ maps 1-to-1 to a page or API group.

🚀

The technology stack

Five layers, each doing one job well.

🚀

Workflow A — Upload a pickled model

The classic pipeline: train offline, upload, benchmark, rank.

  1. 1. Train
    You train a scikit-learn / XGBoost / LightGBM / PyTorch model locally and pickle it with joblib.dump(model, 'model.pkl').
  2. 2. Upload
    POST /models/upload streams the .pkl file to the server. The models.py route stores the file under uploads/, creates a Model row in the DB, and links it to your user account.
  3. 3. Benchmark
    Pick a dataset, click Benchmark. The benchmark.py route loads the pickle, loads the dataset, runs predict() / predict_proba() on a holdout split, and computes accuracy/F1/RMSE depending on task type.
  4. 4. Leaderboard
    The result row is inserted into leaderboard_entries. A broadcast is sent on /ws/leaderboard, and every browser currently viewing the leaderboard sees the new row appear without refreshing.
  5. 5. Compete
    Optionally submit the model to a competition. competition_detail.html shows your submission, ranks it against others, and lets you post discussion comments.
End-to-end upload & benchmark flow
Trainjoblib.dump()
→
UploadPOST /models/upload
→
Pickle storeduploads/*.pkl
Pick dataset/benchmark
→
Benchmarkfit + predict
→
Scoreaccuracy / F1 / RMSE
Insert rowleaderboard_entries
→
Broadcast WS/ws/leaderboard
→
Browser updatesDOM patch, no reload
🚀

Workflow B — Paste code, get a pickled model

Skip the local Python install entirely.

  1. 1. Paste
    Open /convert and paste a Python snippet that trains a model. The page auto-detects the framework (sklearn / xgboost / lightgbm) by grepping your code for import statements.
  2. 2. Run server-side
    Click Train. The snippet runs in a fresh server-side namespace with scikit-learn, xgboost, etc. already installed. Matplotlib figures are captured and rendered inline.
  3. 3. Pickle
    On success, the trained model is joblib.dump()'d to a temp file and POSTed to /api/convert/upload-pickle, which creates a Model row exactly like the manual upload path.
  4. 4. Benchmark
    The model is now in your library — pick it on the Benchmark page and run it against any dataset.
Paste-code → pickled-model flow
Paste code/convert
→
Auto-detectsklearn / xgb / lgbm
→
Run server-sidefresh namespace
Capture figuresmatplotlib → PNG
→
Pickle modeljoblib.dump
→
POST upload-picklecreates Model row
🚀

Workflow C — Colab-style Notebook

Persistent kernel + shell + real terminal, all in the browser.

  1. 1. Open /notebook
    A _SessionState is created for your user — a Python namespace dict + threading.Lock + cell counter + installed-packages list. TTL is 30 minutes; cap is 50 sessions.
  2. 2. Write cells
    Each code cell is sent to POST /api/notebook/cell with the source. The handler runs exec(code, session.namespace) under the lock, captures stdout/stderr via redirect, and extracts any matplotlib figures as base64 PNGs.
  3. 3. Shell commands
    Prefix a line with ! (e.g. !pip install xgboost) and it's routed through _execute_shell_command — an allowlist (pip, python, ls, ...) + pattern blocklist (rm -rf /, sudo, curl|sh, ...). pip auto-injects --break-system-packages for PEP 668.
  4. 4. Magics
    %whos lists variables. %time wraps a statement with timeit. %reset clears the namespace. %pip routes through the same shell path.
  5. 5. Terminal tab
    Click the Terminal tab and xterm.js opens a WebSocket to /api/notebook/terminal. The server spawns a real PTY bash subprocess (cwd /tmp, 30-min idle timeout) and pipes bytes both ways. You get a full bash shell — vim, top, ipython, git, everything.
Notebook request lifecycle
Open /notebookcreate session
→
_SessionStatenamespace dict + lock
→
Run cellPOST /api/notebook/cell
!shellallowlist + blocklist
→
%magic%whos / %time / %reset
→
Figures + suggestionsbase64 PNG + pip hints
Terminal tabxterm.js
→
WebSocket/api/notebook/terminal
→
PTY bashcwd /tmp, 30-min TTL
🚀

Workflow D — Real-time fan-out

How a benchmark in Tokyo reaches your browser in Berlin in <100ms.

  1. 1. Benchmark completes
    benchmark.py finishes scoring a model. It builds a JSON event {type: 'leaderboard_update', dataset_id, model_id, score}.
  2. 2. Broadcast
    ws_manager.broadcast(event) iterates over every active WebSocket connection and sends the JSON.
  3. 3. Browser receives
    competition_detail.html has an open /ws/leaderboard socket. Its onmessage handler matches the dataset_id, then fetches the fresh leaderboard HTML from the API.
  4. 4. DOM patch
    The new rows replace the old tbody.innerHTML. No full page reload — just the table body swaps.
Real-time fan-out path
Benchmark donebenchmark.py
→
Build event JSON{type, dataset_id, score}
→
ws_manager.broadcastiterate active conns
Browser WS onmessagecompetition_detail.html
→
Fetch fresh HTMLGET /api/.../leaderboard
→
tbody.innerHTML = DOM patch
🚀

Authentication & security

Cookie-based JWT, scoped sessions, sandboxed execution.

Auth & sandbox defence in depth
LoginPOST /api/auth/login
→
JWT signedHS256 + SECRET_KEY
→
httpOnly cookieSameSite=Lax
Every requestcookie sent automatically
→
get_current_userverify sig + expiry
→
user in contexttemplate gets user
!pip install xnotebook shell
→
Allowlistpip in allowed set?
→
Blocklistrm -rf / blocked?
Start learning → Try the notebook Try convert View source on GitHub