> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trainy.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Weights & Biases Migration

> How to migrate from Weights & Biases to Pluto with zero code changes using the dual-logging hook.

<Warning>
  The wandb compatibility shim is in **public preview**. Its interface and behavior may change as we iterate. Expect sharp edges.
</Warning>

We've created a Weights & Biases compatibility layer that enables dual-logging to both wandb and Pluto simultaneously. This allows you to gradually migrate your experiment tracking without touching existing training scripts.

## Quick Start

Install Pluto and authenticate. Use either `pluto login` (stores a token in your system keyring — recommended for interactive workstations) **or** export `PLUTO_API_KEY` (recommended for CI / containers / non-interactive jobs):

```bash theme={null}
pip install pluto-ml

# Pick one:
pluto login                          # interactive — stores token in keyring
# export PLUTO_API_KEY=mlpi_xxx      # or set the env var
```

Then run any existing wandb script — dual-logging activates automatically:

```python theme={null}
import wandb

# Project that the run is recorded to
project = "my-awesome-project"

# Dictionary with hyperparameters
config = {
    'epochs': 10,
    'lr': 0.01,
}

with wandb.init(project=project, config=config) as run:
    # Training code here
    # Log values to W&B with run.log()
    run.log({"accuracy": 0.9, "loss": 0.1})
```

That's it. Every `wandb.log()` call now also logs to Pluto. No `PLUTO_PROJECT` env var needed — the shim picks up the `project=` kwarg from `wandb.init()`.

## Configuration

### Authentication

Either of the following is sufficient — the hook checks both:

| Source                  | When to use                                                                                                                           |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `pluto login`           | Interactive workstations. Stores a token in your system keyring; persists across shells.                                              |
| `PLUTO_API_KEY` env var | CI, containers, or any non-interactive context. In `DISABLE_WANDB_LOGGING=true` mode, `WANDB_API_KEY` may be reused as a Pluto token. |

If neither is present, the shim logs a one-time warning pointing at `pluto login` / `PLUTO_API_KEY` and wandb runs unmodified.

### Project Name

Resolved in this order (first match wins):

| Source                                   | Notes                                                                        |
| ---------------------------------------- | ---------------------------------------------------------------------------- |
| `PLUTO_PROJECT` env var                  | Highest precedence.                                                          |
| `project=` kwarg to `wandb.init(...)`    | Picked up automatically — no extra config needed.                            |
| `WANDB_PROJECT` env var                  | Falls back to wandb's own project env so you don't need to duplicate config. |
| `run.project` attribute on the wandb run | Last-resort fallback.                                                        |

### Optional Environment Variables

| Variable                | Description                                                                               |
| ----------------------- | ----------------------------------------------------------------------------------------- |
| `PLUTO_URL_APP`         | App endpoint for self-hosted instances                                                    |
| `PLUTO_URL_API`         | API endpoint for self-hosted instances                                                    |
| `PLUTO_URL_INGEST`      | Ingest endpoint for self-hosted instances                                                 |
| `DISABLE_WANDB_LOGGING` | Set to `true` to skip wandb entirely and only log to Pluto (post-sunset mode, see below). |

## Supported Operations

The compatibility layer monkey-patches `wandb.init()` so the returned `Run` object dual-logs every supported call. Unsupported methods still work normally on wandb via attribute fallthrough — they just don't dual-log to Pluto.

### Initialization

| wandb                                          | pluto                                          |
| ---------------------------------------------- | ---------------------------------------------- |
| `wandb.init(project="my-project", config=cfg)` | `pluto.init(project="my-project", config=cfg)` |
| `wandb.init(fork_from=...)`                    | `pluto.init(fork_run_id=..., fork_step=...)`   |
| `run.tags = ["experiment-v1"]`                 | `run.add_tags(["experiment-v1"])`              |

`wandb.init()` completes fully before any Pluto code runs. `pluto.init()` runs in a thread with a 10s timeout — if the Pluto server is unreachable, the run silently falls back to wandb-only. Tag assignments on the wandb run sync to Pluto on every assignment.

### Metric Logging

| wandb                                      | pluto                                    |
| ------------------------------------------ | ---------------------------------------- |
| `wandb.log({"train/loss": 0.5})`           | `run.log({"train/loss": 0.5})`           |
| `wandb.log({"train/loss": 0.5}, step=100)` | `run.log({"train/loss": 0.5}, step=100)` |

Numeric values, lists of numbers, and the wandb media types below are forwarded to Pluto. The `data` dict you pass into `wandb.log()` is never mutated.

### Media Logging

| wandb                  | pluto equivalent       |
| ---------------------- | ---------------------- |
| `wandb.Image(...)`     | `pluto.Image(...)`     |
| `wandb.Histogram(...)` | `pluto.Histogram(...)` |
| `wandb.Audio(...)`     | `pluto.Audio(...)`     |
| `wandb.Video(...)`     | `pluto.Video(...)`     |
| `wandb.Table(...)`     | Pluto table file       |

Lists of media at the same step (`wandb.log({"gens": [wandb.Image(a), wandb.Image(b)]})`) are forwarded as a multi-sample group. The Pluto UI renders these with a per-card `◀ i / N ▶` nav — see [Images: Multi-Sample Logging](/pluto/visualizations/images#multi-sample-logging).

### Artifacts and Saved Files

| wandb                      | pluto equivalent                                                                             |
| -------------------------- | -------------------------------------------------------------------------------------------- |
| `wandb.log_artifact(art)`  | Each local file in the artifact → `pluto.Artifact` under `artifacts/{art_name}/{entry_path}` |
| `wandb.save(path_or_glob)` | Each matched file → `pluto.Artifact` under `save/{basename}`                                 |

Reference entries (S3 URLs, etc.) inside `wandb.Artifact` are skipped — Pluto stores files directly. Artifact versions and aliases are not translated; Pluto has no equivalent.

### Finish

`wandb.finish()` triggers `pluto.finish()` as well. Pluto's teardown has a 5s timeout so it never blocks wandb's cleanup. If `pluto.init()` failed earlier, the run stays wandb-only and `finish()` is a no-op on the Pluto side.

## Not Supported

These wandb features run normally on wandb but **do not** dual-log to Pluto:

| wandb feature                                  | Reason                                                                                                                        |
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `run.config.update()` post-init                | Compat layer captures config only at `wandb.init()`. Call `run.update_config()` directly on the Pluto run for in-run updates. |
| `run.watch()` (gradient tracking)              | No Pluto equivalent.                                                                                                          |
| `wandb.log_model()` / model registry           | No Pluto equivalent.                                                                                                          |
| `wandb.log_code()`                             | No Pluto equivalent.                                                                                                          |
| `define_metric()`, `mark_preempting()`, sweeps | No Pluto equivalent.                                                                                                          |

## Post-Sunset Mode

When you're ready to stop sending data to wandb, set the kill switch:

```bash theme={null}
export DISABLE_WANDB_LOGGING=true
```

In disabled mode, `WANDB_API_KEY` can also hold a Pluto API token, so a user fully migrating from wandb can swap a single env var value:

```bash theme={null}
export WANDB_API_KEY=mlpi_xxx       # Pluto token in the existing var
export WANDB_PROJECT=my-project
export DISABLE_WANDB_LOGGING=true
python train.py
```

All `wandb.*` calls are intercepted and redirected to Pluto without any code changes.
