OpenRunner SDK - W&B-compatible ML experiment tracking client
Project description
OpenRunner SDK
Open-source, self-hosted ML experiment tracking — a drop-in replacement for Weights & Biases.
Install
pip install openrunner-sdk
Setup
export OPENRUNNER_API_KEY="or_your_key"
export OPENRUNNER_BASE_URL="https://your-server.com"
Or use the CLI:
openrunner login
Quick Start
import openrunner
# Start a run
openrunner.init(project="my-project", config={"lr": 0.001, "epochs": 10})
# Log metrics in your training loop
for epoch in range(10):
loss = train(epoch)
acc = evaluate()
openrunner.log({"loss": loss, "accuracy": acc, "epoch": epoch})
# End the run
openrunner.finish()
API Reference
Core Functions
openrunner.init()
Initialize a new experiment run.
run = openrunner.init(
project="my-project", # Project name (auto-created if missing)
name="experiment-1", # Optional display name
config={"lr": 0.001}, # Hyperparameters
tags=["baseline", "v2"], # Optional tags
notes="Testing new arch", # Optional notes
group="sweep-1", # Optional group name
job_type="train", # Optional job type
resume=True, # Resume a previous run by ID
)
openrunner.log()
Log metrics. Non-blocking — never slows down training.
# Basic logging
openrunner.log({"loss": 0.5, "accuracy": 0.85})
# With explicit step
openrunner.log({"loss": 0.3}, step=100)
# Log images
openrunner.log({"predictions": openrunner.Image(img_array, caption="epoch 5")})
# Log tables
table = openrunner.Table(
columns=["input", "predicted", "actual"],
data=[["img_01", 7, 7], ["img_02", 3, 5]],
)
openrunner.log({"eval_results": table})
openrunner.finish()
End the current run. Flushes all buffered metrics.
openrunner.finish()
openrunner.finish(exit_code=0) # With exit code
openrunner.finish(quiet=True) # Suppress output
Config
Dict-like object with dot notation. Set at init(), accessible throughout the run.
openrunner.init(config={"optimizer": {"lr": 0.001, "weight_decay": 1e-5}})
# Access
print(openrunner.config["optimizer.lr"]) # 0.001 (flattened keys)
print(openrunner.config.optimizer.lr) # 0.001 (dot notation)
# Update after init
openrunner.config.update({"batch_size": 64})
openrunner.config["new_param"] = "value"
Summary
Auto-updated with the last logged value for each key. Can also be set explicitly.
# Auto-populated from log()
openrunner.log({"loss": 0.5})
openrunner.log({"loss": 0.3})
print(openrunner.summary["loss"]) # 0.3 (last value)
# Explicit set
openrunner.summary["best_accuracy"] = 0.95
openrunner.summary["final_loss"] = 0.1
Artifacts
Version datasets, models, and checkpoints with content-hash deduplication.
# Log a model artifact
artifact = openrunner.Artifact(name="my-model", type="model")
artifact.add_file("model.pth")
artifact.add_file("config.json")
run.log_artifact(artifact)
# Use an artifact from a previous run
artifact = run.use_artifact("my-model:v2")
artifact.download("/path/to/dir")
Media Types
Images
import numpy as np
# From numpy array
img = openrunner.Image(np.random.rand(28, 28, 3), caption="sample")
# From PIL Image
from PIL import Image as PILImage
pil_img = PILImage.open("photo.png")
img = openrunner.Image(pil_img, caption="photo")
# From file path
img = openrunner.Image("output.png", caption="result")
openrunner.log({"examples": img})
Tables
table = openrunner.Table(
columns=["epoch", "loss", "accuracy"],
data=[
[1, 0.9, 0.65],
[2, 0.5, 0.82],
[3, 0.3, 0.91],
],
)
openrunner.log({"metrics_table": table})
Run Properties
run = openrunner.init(project="test")
print(run.id) # "a1b2c3d4" (8-char ID)
print(run.name) # Display name
print(run.project) # Project name
print(run.config) # Config object
print(run.summary) # Summary object
HTML
# Log raw HTML for rich reports, custom visualizations, or formatted output
openrunner.log({"report": openrunner.Html("<h1>Training Report</h1><p>Loss converged at epoch 42.</p>")})
Histograms
import numpy as np
weights = np.random.randn(10000)
openrunner.log({"weight_dist": openrunner.Histogram(weights, num_bins=50)})
Plotly Charts
import plotly.graph_objects as go
fig = go.Figure(data=go.Scatter(x=[1, 2, 3], y=[4, 5, 6]))
openrunner.log({"interactive_plot": openrunner.Plotly(fig)})
Point Clouds
import numpy as np
points = np.random.randn(1000, 3)
colors = np.random.randint(0, 255, (1000, 3), dtype=np.uint8)
openrunner.log({"lidar": openrunner.PointCloud3D(points, colors=colors)})
Bounding Boxes
img = openrunner.Image("photo.jpg")
boxes = [{"position": {"minX": 10, "minY": 20, "maxX": 100, "maxY": 150}, "class_id": 0}]
openrunner.log({"detections": openrunner.BoundingBoxes2D(img, boxes, class_labels={0: "cat"})})
Audio
import numpy as np
# From numpy array (mono, float32, -1 to 1)
audio = openrunner.Audio(np.random.randn(44100).astype(np.float32), sample_rate=44100)
openrunner.log({"audio_sample": audio})
Video
# From file path
openrunner.log({"demo": openrunner.Video("output.mp4", caption="training demo")})
Matplotlib Figures
import matplotlib.pyplot as plt
plt.figure()
plt.plot([1, 2, 3], [4, 5, 6])
openrunner.log({"chart": openrunner.MatplotlibFigure()}) # captures current figure
plt.close()
LLM Tracing
Trace LLM API calls for debugging and cost tracking.
import openrunner
openrunner.init(project="llm-app")
# Auto-trace OpenAI calls
openrunner.trace.patch_openai()
# Or manually trace any function
@openrunner.trace
def generate(prompt):
return client.chat.completions.create(
model="gpt-4", messages=[{"role": "user", "content": prompt}]
)
Hyperparameter Sweeps
Run distributed hyperparameter searches.
import openrunner
sweep_config = {
"method": "bayes",
"metric": {"name": "val_loss", "goal": "minimize"},
"parameters": {
"lr": {"min": 1e-5, "max": 1e-2, "distribution": "log_uniform"},
"epochs": {"values": [10, 20, 50]},
},
}
sweep_id = openrunner.sweep(sweep_config, project="my-project")
def train():
run = openrunner.init()
lr = openrunner.config.lr
# ... training loop ...
openrunner.finish()
openrunner.agent(sweep_id, function=train, count=20)
Remote Launch
Submit training jobs to remote infrastructure.
import openrunner
job = openrunner.launch(
project="my-project",
config={"lr": 0.001, "epochs": 50},
resource="gpu-a100",
)
job.wait() # block until finished
print(job.state) # "finished"
Model Registry
Version and alias models for production deployment.
# Log a model with aliases
artifact = openrunner.Artifact(name="classifier", type="model")
artifact.add_file("model.pt")
openrunner.link_artifact(artifact, aliases=["staging"])
# Use a model by alias
model_dir = openrunner.use_artifact("classifier:production")
Alerts
Send notifications when training reaches milestones or encounters issues.
openrunner.alert(title="Training complete", text="Final accuracy: 95.2%", level="INFO")
openrunner.alert(title="Loss spike detected", level="WARN")
Query API
Read-only access to runs, metrics, and projects for analysis and dashboards.
api = openrunner.Api()
runs = api.runs("my-project", filters={"state": "finished"})
for run in runs:
print(f"{run.name}: {run.summary.get('accuracy')}")
Migrating from W&B
Change one import — everything else stays the same:
# Before
import wandb
wandb.init(project="my-project")
wandb.log({"loss": 0.5})
wandb.finish()
# After
import openrunner as wandb
wandb.init(project="my-project")
wandb.log({"loss": 0.5})
wandb.finish()
Framework Integrations
PyTorch
from openrunner.integration.pytorch import log_gradients
openrunner.init(project="pytorch-example")
for batch in dataloader:
loss = model(batch)
loss.backward()
log_gradients(model) # Logs gradient norms
optimizer.step()
openrunner.finish()
HuggingFace Transformers
from openrunner.integration.huggingface import OpenRunnerCallback
openrunner.init(project="hf-example")
trainer = Trainer(
model=model,
args=training_args,
callbacks=[OpenRunnerCallback()],
)
trainer.train()
openrunner.finish()
PyTorch Lightning
from openrunner.integration.lightning import OpenRunnerLogger
logger = OpenRunnerLogger(project="lightning-example")
trainer = pl.Trainer(logger=logger)
trainer.fit(model)
Keras
from openrunner.integration.keras import OpenRunnerCallback
openrunner.init(project="keras-example")
model.fit(x_train, y_train, callbacks=[OpenRunnerCallback()])
openrunner.finish()
XGBoost
from openrunner.integration.xgboost import OpenRunnerCallback
openrunner.init(project="xgboost-example")
bst = xgb.train(params, dtrain, callbacks=[OpenRunnerCallback()])
openrunner.finish()
scikit-learn
from openrunner.integration.sklearn import log_model
openrunner.init(project="sklearn-example")
model.fit(X_train, y_train)
log_model(model) # Logs parameters and metrics
openrunner.finish()
FastAI
from openrunner.integration.fastai import OpenRunnerCallback
openrunner.init(project="fastai-example")
learn = cnn_learner(dls, resnet34, cbs=[OpenRunnerCallback()])
learn.fine_tune(5)
openrunner.finish()
LangChain
from openrunner.integration.langchain import OpenRunnerTracer
openrunner.init(project="langchain-example")
tracer = OpenRunnerTracer()
chain.invoke({"input": "Hello"}, config={"callbacks": [tracer]})
openrunner.finish()
Offline Mode
Train without connectivity, sync later:
export OPENRUNNER_MODE=offline
python train.py
# When back online
openrunner sync
Offline runs are stored as JSONL files (human-readable, crash-safe). Sync is additive and idempotent — interrupted syncs resume without data loss.
CLI
# Authenticate
openrunner login
# Sync offline runs
openrunner sync
# List projects and runs
openrunner ls
System Metrics
Automatically collected during training (enabled by default):
- CPU utilization (%)
- System memory usage (%)
- GPU utilization (%) — requires
pip install openrunner-sdk[gpu] - GPU memory usage (%)
Disable with:
export OPENRUNNER_SYSTEM_METRICS=false
Environment Variables
| Variable | Description | Default |
|---|---|---|
OPENRUNNER_API_KEY |
API key for authentication | (required) |
OPENRUNNER_BASE_URL |
Server URL | http://localhost:8000 |
OPENRUNNER_PROJECT |
Default project name | (none) |
OPENRUNNER_MODE |
online or offline |
online |
OPENRUNNER_SYSTEM_METRICS |
Enable system metrics | true |
OPENRUNNER_OFFLINE_DIR |
Offline storage directory | ~/.openrunner/offline |
W&B env vars (WANDB_API_KEY, WANDB_BASE_URL) are also supported as fallback for migration.
Self-Hosting
OpenRunner is designed to be self-hosted. See the main repo for server setup with Docker Compose.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openrunner_sdk-2.18.0.tar.gz.
File metadata
- Download URL: openrunner_sdk-2.18.0.tar.gz
- Upload date:
- Size: 255.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d3e71e89333e1442664547728ce551377938879a160507ed427d429f4f41bacf
|
|
| MD5 |
3897bf1bf944fca88840c2ce2bd5b76d
|
|
| BLAKE2b-256 |
adacf0f661c4316c80d17c34c8ff9adf15f795526a8ac0e1c8bfd44a1af70a9c
|
File details
Details for the file openrunner_sdk-2.18.0-py3-none-any.whl.
File metadata
- Download URL: openrunner_sdk-2.18.0-py3-none-any.whl
- Upload date:
- Size: 226.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e4aa1bcfb18ee3189389ffbd4a1fe89c039f23dc387bffe41658c6d5dcac65f
|
|
| MD5 |
a6ef94cd35533630ec3427f8c6c5ed4b
|
|
| BLAKE2b-256 |
0668fd073d53afd7eb5c85c638341256d8e6dc6c5c24ff21342c5d446fa1fadc
|