Skip to main content

OpenRunner SDK

PyPI License: MIT Python 3.10+

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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openrunner_sdk-2.37.4.tar.gz (487.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openrunner_sdk-2.37.4-py3-none-any.whl (441.6 kB view details)

Uploaded Python 3

File details

Details for the file openrunner_sdk-2.37.4.tar.gz.

File metadata

  • Download URL: openrunner_sdk-2.37.4.tar.gz
  • Upload date:
  • Size: 487.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for openrunner_sdk-2.37.4.tar.gz
Algorithm Hash digest
SHA256 ac8bd5c1f8713502201d366c01f67563c8e2cccd3837ff9b4252c47e46c7f110
MD5 f953225034a02c38d1e6c165027d7182
BLAKE2b-256 b127ac868470f877aacb4d81ad1c19f1d454053214b2a659238aa8f40ea29e01

See more details on using hashes here.

File details

Details for the file openrunner_sdk-2.37.4-py3-none-any.whl.

File metadata

  • Download URL: openrunner_sdk-2.37.4-py3-none-any.whl
  • Upload date:
  • Size: 441.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for openrunner_sdk-2.37.4-py3-none-any.whl
Algorithm Hash digest
SHA256 ec7321d744003989886b413cf7510d22c15ed688ba8482b9375a00d9696f96cd
MD5 1c9002084e576450c730b45482e22ab8
BLAKE2b-256 cc53b84a1365efcc35238fc6a8dc6621d70527d4f6f1ebedbcfd6e936c13cc52

See more details on using hashes here.

Release history Release notifications | RSS feed

2.41.7

2 files

2.41.6

2 files

2.41.5

2 files

2.41.4

2 files

2.41.3

2 files

2.41.2

2 files

2.41.1

2 files

2.41.0

2 files

2.40.1

2 files

2.40.0

2 files

2.39.0

2 files

2.38.3

2 files

2.38.2

2 files

2.38.1

2 files

2.38.0

2 files

2.37.36

2 files

2.37.35

2 files

2.37.34

2 files

2.37.33

2 files

2.37.32

2 files

2.37.31

2 files

2.37.30

2 files

2.37.29

2 files

2.37.28

2 files

2.37.27

2 files

2.37.26

2 files

2.37.25

2 files

2.37.24

2 files

2.37.23

2 files

2.37.22

2 files

2.37.21

2 files

2.37.20

2 files

2.37.19

2 files

2.37.18

2 files

2.37.17

2 files

2.37.16

2 files

2.37.15

2 files

2.37.14

2 files

2.37.13

2 files

2.37.12

2 files

2.37.11

2 files

2.37.10

2 files

2.37.9

2 files

2.37.8

2 files

2.37.7

2 files

2.37.6

2 files

2.37.5

2 files

This release

2.37.4 This release

2 files

2.37.1

2 files

2.37.0

2 files

2.25.0

2 files

2.24.2

2 files

2.24.1

2 files

2.24.0

2 files

2.23.0

2 files

2.22.0

2 files

2.21.0

2 files

2.20.9

2 files

2.20.8

2 files

2.20.7

2 files

2.20.6

2 files

2.20.5

2 files

2.20.4

2 files

2.20.3

2 files

2.20.2

2 files

2.20.1

2 files

2.20.0

2 files

2.19.2

2 files

2.19.1

2 files

2.19.0

2 files

2.18.6

2 files

2.18.5

2 files

2.18.4

2 files

2.18.3

2 files

2.18.2

2 files

2.18.1

2 files

2.18.0

2 files

2.17.4

2 files

2.17.3

2 files

2.17.2

2 files

2.17.1

2 files

2.17.0

2 files

2.16.7

2 files

2.16.6

2 files

2.16.5

2 files

2.16.4

2 files

2.16.3

2 files

2.16.2

2 files

2.16.1

2 files

2.16.0

2 files

2.15.6

2 files

2.15.5

2 files

2.15.4

2 files

2.15.3

2 files

2.15.2

2 files

2.15.1

2 files

2.15.0

2 files

2.14.4

2 files

2.14.3

2 files

2.14.2

2 files

2.14.1

2 files

2.14.0

2 files

2.13.4

2 files

2.13.3

2 files

2.13.2

2 files

2.13.1

2 files

2.13.0

2 files

2.12.0

2 files

2.11.0

2 files

2.10.0

2 files

2.9.0

2 files

2.8.0

2 files

2.7.1

2 files

2.7.0

2 files

2.6.0

2 files

2.5.0

2 files

2.4.4

2 files

2.4.3

2 files

2.4.2

2 files

2.4.1

2 files

2.4.0

2 files

2.3.0

2 files

2.2.0

2 files

2.1.0

2 files

2.0.0

2 files

1.6.0

2 files

1.5.0

2 files

1.4.0

2 files

1.3.0

2 files

1.2.0

2 files

1.1.0

2 files

1.0.0

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page