Skip to main content

ML-Dash

A simple and flexible SDK for ML experiment tracking and data storage with background buffering for high-performance training.

Features

Core Features

  • Three Usage Styles: Pre-configured singleton (dxp), context manager, or direct instantiation
  • Dual Operation Modes: Remote (API server) or local (filesystem)
  • OAuth2 Authentication: Secure device flow; the SDK reads the token the ml-dash CLI stores
  • Auto-creation: Automatically creates namespace, project, and folder hierarchy
  • Upsert Behavior: Updates existing experiments or creates new ones
  • Experiment Lifecycle: Automatic status tracking (RUNNING, COMPLETED, FAILED, CANCELLED)
  • Organized File Storage: Prefix-based file organization with unique snowflake IDs
  • Rich Metadata: Tags, bindrs, descriptions, and custom metadata support
  • Simple API: Minimal configuration, maximum flexibility

Performance Features (New in 0.6.7)

  • Background Buffering: Non-blocking I/O operations eliminate training interruptions
  • Automatic Batching: Time-based (5s) and size-based (100 items) flush triggers
  • Track API: Time-series data tracking for robotics, RL, and sequential experiments
  • Numpy Image Support: Direct saving of numpy arrays as PNG/JPEG images
  • Parallel Uploads: ThreadPoolExecutor for efficient file uploads

Nymph job Experiments broker (0.11.0)

The worker integration supplies DREAMLAKE_EXPERIMENT_BROKER and DREAMLAKE_EXPERIMENT_BROKER_TOKEN to the job process. These select a local memory-only broker; they are not DreamLake or Dash user credentials. With that environment, Experiment() automatically uses the platform's pre-created run:

from ml_dash import Experiment

with Experiment().run as exp:
    exp.params.set(lr=0.001)
    exp.metrics("loss").log(step=0, loss=0.1)
    exp.flush()

Closing the SDK logging scope flushes data; it does not complete or cancel the compute task. DreamLake projects the execution receipt's terminal state onto the experiment. Calling the job client's status mutation directly is rejected. The returned results URL selects the exact run with one ?run= parameter.

ManagedConnection.from_job() also explicitly selects the same broker. The broker must be literal HTTP loopback (127.0.0.1 or [::1]) with an explicit port and no path, credentials, query or fragment. Each renewed lease goes back through the broker, where the worker checks the live job attempt and project authorization. Leases expire within 60 seconds; the SDK validates that expiry and fixes the instance, project, run, workload, generation, API URL and experiment page across renewals. The SDK reuses the existing run rather than creating one.

An explicit different prefix, another managed connection, standalone server, or custom local storage conflicts with job scope and is rejected. Partial broker environment, revocation, terminal jobs, stale attempts and changed destinations fail without falling back to standalone login, Keychain or local storage. Keep broker credentials in worker-provided process memory/environment; do not print, export into training configuration, or persist them. No long-lived user token is required in the job. The broker authorizes an exact task run, not arbitrary runs.

This integration is included in SDK 0.11.0 and requires the matching DreamLake BFF job-session routes, Dash backend, control plane, and opt-in Nymph 0.1.28 worker broker. Installing the SDK does not upgrade an existing worker or launch a task. Production compute execution has not been accepted in this release; the worker-to-SDK flow is covered by local integration tests. Source-backed storage remains outside this increment. The explicit application JobLifecycle contract below is separate and unchanged.

DreamLake job lifecycle (explicit opt-in)

JobLifecycle reports application outcomes through the existing authenticated DreamLake run API. It does not infer an outcome from Nymph process exit, experiment status, inactivity, or an interpreter exit hook. Existing experiments without this option keep their behavior.

from ml_dash import Experiment, JobLifecycle

lifecycle = JobLifecycle(
    api_url="https://api.dreamlake.ai",
    namespace="your-namespace",
    job_id=tracked_run_id,
    attempt_id=tracked_run_exec_id,
    token=dreamlake_access_token,  # supplied explicitly; independent of Dash auth
    journal_dir="/durable/private/job-attempt-lifecycle",
)
with Experiment(prefix="your-namespace/project/run", job_lifecycle=lifecycle).run:
    train()

Pass the exact existing tracked run ID and its stored execution ID; names, experiment prefixes, and environment variables are never used to guess a binding. Use the base URL for the API that owns /namespaces/{namespace}/runs/{job_id}. The token must authorize that namespace and run. The journal never stores tokens.

The existing run.start(), complete(), fail(), and cancel() contract reports running, succeeded, failed, and cancelled. Context-manager exit reports completion only when the body returns normally; exceptions report failure. Buffered-data flush failure keeps the SDK's existing completion-to-failure rule. Terminal evidence is durably recorded before the unrelated Dash experiment status request. Reporting errors propagate; they never manufacture an acknowledgment.

Use a dedicated private directory on durable local POSIX storage (mode 0700). Events and acknowledgments are atomically replaced and fsynced, and a nonblocking OS lock rejects concurrent writers. Do not put this directory on ephemeral storage or filesystems without local locking and fsync guarantees. Keep the directory after completion: it binds immutable event IDs to one exact API URL, namespace, job, and attempt. Reusing it with another binding fails before any request.

After a network error or process restart, reconstruct JobLifecycle with the same binding and directory and call lifecycle.flush() to replay pending events. A lost acknowledgment replays the original event ID and payload. flush() only sends already-recorded evidence; it never creates completion. For a restarted application, call run.start() again only if there is no recorded terminal outcome. A journal with terminal evidence cannot begin another application execution. There is no background sender or automatic restart hook: the caller must explicitly retry or resume delivery. Missing terminal evidence remains unknown.

Installation

DreamLake managed Experiments (since 0.10.0)

The SDK supports ManagedConnection.from_login(org, project) and Experiment(prefix="org/project/run", managed=connection). This uses DreamLake project permissions and the existing DreamLake login; it does not require another Dash organization. Matching server and CLI releases are required. See the authoritative managed setup and Python guide. Managed credentials are short lived, renewed in memory, and never exported into plans. The managed transport currently supports flat run paths, parameters, metrics, logs, lifecycle status, and root attachments up to 8 MiB. Standalone logging remains available and unchanged.

This repo is the Python SDK — the library you import ml_dash from. The ml-dash command line is a separate program, distributed on npm; see The CLI moved to npm below.

SDK (this package)

Using uv (recommended) Using pip
uv add ml-dash
pip install ml-dash

CLI

The CLI is distributed as @dreamlake/ml-dash on npm. Check the registry or the original releases for available versions. With Node.js >= 20.19:

npm install -g @dreamlake/ml-dash

Or a self-contained binary, needing neither Node.js nor Python:

# macOS / Linux
curl -fsSL https://pub-42e1dcc7de574d4a92984865fdc95f10.r2.dev/install.sh | sh
# Windows PowerShell
irm https://pub-42e1dcc7de574d4a92984865fdc95f10.r2.dev/install.ps1 | iex

On Alpine the musl builds need apk add --no-cache libstdc++.

The package is scoped because the unscoped ml-dash name is not claimable on npm, but the command is still ml-dash. Either channel updates itself, in place and through the channel it was installed from:

ml-dash update --check   # report whether a newer release exists
ml-dash update           # install it

The CLI moved to npm

Up to and including 0.6.27, pip install ml-dash also put an ml-dash executable on your PATH. From 0.7.0 it does not: the command line has been rewritten in TypeScript and ships on its own — as the npm package @dreamlake/ml-dash or the standalone installer above — so it installs and updates without touching your training environment's Python dependencies. Upgrading the Python package to 0.7.0 removes the old executable; install the new CLI alongside it.

Nothing about the SDK changes. pip install ml-dash is still how you get ml_dash, and every Experiment, files, tracks, and storage API is untouched.

Before Now
SDK (import ml_dash) pip install ml-dash pip install ml-dash
CLI (ml-dash login, upload, …) pip install ml-dash npm install -g @dreamlake/ml-dash, or the standalone installer

The command names and arguments carry over, and the two share a credential store: the CLI writes its token to the same OS keyring entry (and the same ~/.dash/ fallback files) that ml_dash.auth.token_storage reads, so ml-dash login still authenticates your Python code and an existing valid login is normally picked up as-is. Re-run ml-dash login if it is not.

Command behaviour is not identical — the rewrite changes and fixes a number of things — and the CLI's own release notes are where those differences are described.

If you were importing ml_dash.cli or ml_dash.cli_commands.* directly from Python — an unsupported path, but a real one — those modules are gone. Shell out to the ml-dash binary instead.

Releases up to 0.6.27 keep the old Python CLI; pin ml-dash<0.7 only if you cannot install the new one yet.

Quick Start

1. Authenticate (Required for Remote Mode)

npm install -g @dreamlake/ml-dash   # one time; requires Node.js >= 20.19
                                    # (or use the standalone installer above)
ml-dash login

This opens your browser for secure OAuth2 authentication. Your credentials are stored securely in your system keychain — where the Python SDK reads them.

2. Start Tracking Experiments

Option A: Use the Pre-configured Singleton (Easiest)

from ml_dash.auto_start import dxp

# Start experiment (uploads to https://api.dash.ml by default)
with dxp.run:
    dxp.log("Training started", level="info")
    dxp.params.set(learning_rate=0.001, batch_size=32)

    for epoch in range(10):
        loss = train_one_epoch()
        dxp.metrics("train").log(loss=loss, epoch=epoch)

Option B: Create Your Own Experiment

from ml_dash import Experiment

with Experiment(
  prefix="alice/my-project/my-experiment",
  dash_url="https://api.dash.ml",  # token auto-loaded
).run as experiment:
  experiment.log("Hello!", level="info")
  experiment.params.set(lr=0.001)

Option C: Local Mode (No Authentication Required)

from ml_dash import Experiment

with Experiment(
  project="my-project", prefix="my-experiment", dash_root=".dash"
).run as experiment:
  experiment.log("Running locally", level="info")

New Features in 0.6.7

🚀 Background Buffering (Non-blocking I/O)

All write operations are now buffered and executed in background threads:

with Experiment("my-project/exp").run as experiment:
    for i in range(10000):
        # Non-blocking! Returns immediately
        experiment.log(f"Step {i}")
        experiment.metrics("train").log(loss=loss, accuracy=acc)
        experiment.files("frames").save_image(frame, to=f"frame_{i}.jpg")

    # All data automatically flushed when context exits

Configure buffering via environment variables:

export ML_DASH_BUFFER_ENABLED=true
export ML_DASH_FLUSH_INTERVAL=5.0
export ML_DASH_LOG_BATCH_SIZE=100

📊 Track API (Time-Series Data)

Perfect for robotics, RL, and sequential experiments. Supports timestamp inheritance for synchronized multi-modal data and track slicing for efficient querying.

with Experiment("robotics/training").run as experiment:
    for step in range(1000):
        # First track auto-generates timestamp
        experiment.tracks("robot/position").append(
            step=step,
            x=position[0],
            y=position[1],
            z=position[2]
        )

        # Other tracks inherit same timestamp with _ts=-1 (synchronized!)
        experiment.tracks("camera/left").append(width=640, height=480, _ts=-1)
        experiment.tracks("robot/velocity").append(vx=0.1, vy=0.0, _ts=-1)
        experiment.tracks("sensors/lidar").append(ranges=[1.5, 2.0], _ts=-1)

    experiment.tracks.flush()

    # Query synchronized data with floor-match timestamp queries
    pose_slice = experiment.tracks("robot/position").slice(0.0, 10.0)

    # Single timestamp query
    entry = pose_slice.findByTime(5.5)  # Returns entry at timestamp 5.0

    # Batch queries
    entries = pose_slice.findByTime([1.0, 3.5, 7.0])  # Returns list of 3 entries

    # Iterate through time range
    for entry in pose_slice:
        print(entry["timestamp"], entry["x"], entry["y"])

See the Tracks guide for complete documentation.

🖼️ Numpy Image Support

Save numpy arrays directly as images (PNG/JPEG):

import numpy as np

with Experiment("vision/training").run as experiment:
    # From MuJoCo, OpenCV, PIL, etc.
    pixels = renderer.render()  # numpy array

    # Save as PNG (lossless)
    experiment.files("frames").save_image(pixels, to="frame.png")

    # Save as JPEG with quality control
    experiment.files("frames").save_image(pixels, to="frame.jpg", quality=85)

    # Auto-detection also works
    experiment.files("frames").save(pixels, to="frame.jpg")

See CHANGELOG.md for complete release notes.

Development Setup

Installing Dev Dependencies

To contribute to ML-Dash or run tests, install the development dependencies:

Using uv (recommended) Using pip
uv sync --extra dev
pip install -e ".[dev]"

This installs:

  • pytest>=8.0.0 - Testing framework
  • pytest-asyncio>=0.23.0 - Async test support
  • ruff>=0.3.0 - Linter and formatter
  • mypy>=1.9.0 - Type checker

The Sphinx toolchain is gone with the docs tree — see Documentation below.

Running Tests

Using uv Using pytest directly
uv run pytest
pytest

Documentation

The docs live at docs.dash.ml and are built from dreamlake-ai/dash-workspace (docs/), not from this repo. The Sphinx tree that used to sit in docs/ and the Docusaurus site in website/ have both been retired — they had drifted apart from each other and from the SDK, and one of them documented _ts as a required argument that raises ValueError when it is optional and raises ConfigurationError.

Doc changes therefore go to that repo. It runs a check:sdk guard that verifies every python snippet against the installed ml_dash, so a signature change here will fail the docs build there rather than sit unnoticed.

The skills/dash-docs/ directory is a vendored copy of the generated agent skill. Never edit it by hand:

make sync-skill    # refresh from docs.dash.ml
make check-skill   # fail if the vendored copy is stale

For maintainers, to build and publish a new release: uv build && uv publish (this publishes the SDK only — the CLI is released from its own npm repo).

Metadata

Release files for ml-dash 0.11.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ml-dash 0.11.0
File Size Uploaded
ml_dash-0.11.0.tar.gz 105.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ml-dash 0.11.0
File Interpreter ABI Platform
ml_dash-0.11.0-py3-none-any.whl Python 3 none any Details

Total release size: 219.2 kB

Release files / ml_dash-0.11.0.tar.gz

Download URL ml_dash-0.11.0.tar.gz
Size 105.5 kB
Tags Source
SHA-256 checksum
How to use checksums
d9e95a22776cdceee2d31798e3a49adeb9f2d106950645cded5cf3fd93139659
BLAKE2b-256 checksum
How to use checksums
269f322fe3840c2f28e1eb1e1c56a77d3f89fc04aa6aadb1f16fd3ae41ac1c4c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / ml_dash-0.11.0-py3-none-any.whl

Download URL ml_dash-0.11.0-py3-none-any.whl
Size 113.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1bda96fbb79dfda2927f7fb108247b7b084e9ac88f6646aad7662fcd10e657d1
BLAKE2b-256 checksum
How to use checksums
6078990c54be434d0a2d77c29e8c0ee7c211e564b2f52ff608d922445761e9db
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.11.0 This release

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.27

2 release files

0.6.26

2 release files

0.6.24

2 release files

0.6.23

2 release files

0.6.22

2 release files

0.6.21

2 release files

0.6.20

2 release files

0.6.18

2 release files

0.6.13

2 release files

0.6.12

2 release files

0.6.11

2 release files

0.6.10

2 release files

0.6.9

2 release files

0.6.7

2 release files

0.6.6

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.9

2 release files

0.5.8

2 release files

0.5.7

2 release files

0.5.6

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.27

1 release file

0.3.26

1 release file

0.3.25

1 release file

0.3.23

1 release file

0.3.22

1 release file

0.3.21

1 release file

0.3.20

1 release file

0.3.18

1 release file

0.3.17

1 release file

0.3.16

1 release file

0.3.15

1 release file

0.3.14

1 release file

0.3.13

1 release file

0.3.12

1 release file

0.3.11

1 release file

0.3.10

1 release file

0.3.7

1 release file

0.3.6

1 release file

0.3.5

1 release file

0.3.4

1 release file

0.3.3

1 release file

0.3.2

1 release file

0.3.0

1 release file

0.2.13

1 release file

0.2.12

1 release file

0.2.11

1 release file

0.2.10

1 release file

0.2.9

1 release file

0.2.8

1 release file

0.2.6

1 release file

0.2.5

1 release file

0.2.4

1 release file

0.2.3

1 release file

0.2.1

2 release files

0.2.0

1 release file

0.1.37

1 release file

0.1.36

1 release file

0.1.35

1 release file

0.1.34

1 release file

0.1.33

1 release file

0.1.32

1 release file

0.1.31

1 release file

0.1.30

1 release file

0.1.29

1 release file

0.1.28

1 release file

0.1.27

1 release file

0.1.26

1 release file

0.1.25

1 release file

0.1.24

1 release file

0.1.23

1 release file

0.1.21

1 release file

0.1.20

1 release file

0.1.19

1 release file

0.1.18

1 release file

0.1.17

1 release file

0.1.16

1 release file

0.1.15

1 release file

0.1.14

1 release file

0.1.13

1 release file

0.1.12

1 release file

0.1.11

1 release file

0.1.10

1 release file

0.1.9

1 release file

0.1.8

1 release file

0.1.7

1 release file

0.1.6

1 release file

0.1.5

1 release file

0.1.4

1 release file

0.1.3

1 release file

0.1.1

1 release file

0.1.0

1 release file

0.0.29

1 release file

0.0.28

1 release file

0.0.27

1 release file

0.0.26

1 release file

0.0.25

1 release file

0.0.24

1 release file

0.0.23

1 release file

0.0.22

1 release file

0.0.21

1 release file

0.0.20

1 release file

0.0.19

1 release file

0.0.18

2 release files

0.0.17

2 release files

0.0.16

2 release files

0.0.15

1 release file

0.0.14

1 release file

0.0.13

1 release file

0.0.12

1 release file

0.0.11

1 release file

0.0.10

1 release file

0.0.9

1 release file

0.0.8

1 release file

0.0.7

1 release file

0.0.6

1 release file

0.0.5

1 release file

0.0.4

1 release file

0.0.3

1 release file

0.0.2

1 release file

0.0.1

1 release file

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