> ## 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.

# Querying Runs

> Read-only helpers for fetching run metadata, metrics, files, and logs from Python.

The `pluto.query` submodule exposes read-only helpers for fetching run data without writing your own HTTP client. Use these when you want to pull metrics into a notebook, compare runs in a script, or download artifacts from a finished training job. For the underlying HTTP API, see the [API Reference](/pluto/api-reference/introduction).

Every helper that takes a run ID accepts either a numeric ID (e.g. `12345`) or a display ID (e.g. `"MMP-42"`).

```python theme={null}
import pluto

run = pluto.query.get_run("my-project", "MMP-42")                     # display ID
metrics = pluto.query.get_metrics("my-project", 12345, ["train/loss"]) # numeric ID
files = pluto.query.get_files("my-project", "MMP-42")
```

## Helpers

| Helper                                                                                      | Returns                                                                                                                             |
| ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `pluto.query.list_projects()`                                                               | All projects you have access to.                                                                                                    |
| `pluto.query.list_runs(project, search=None, tags=None, sort=None, filters=None, ...)`      | Filtered list of runs — see [Filtering runs](#filtering-runs).                                                                      |
| `pluto.query.get_run(project, run_id)`                                                      | Run metadata: name, project, status, tags, config, timestamps.                                                                      |
| `pluto.query.get_metric_names(project, run_id)`                                             | The set of metric names logged on the run.                                                                                          |
| `pluto.query.get_metrics(project, run_id, metric_names=None, step_min=None, step_max=None)` | Time series for the requested metric names. `step_min` / `step_max` fetch just a window of steps (inclusive) — e.g. around a spike. |
| `pluto.query.get_statistics(project, run_id, metric_names=None)`                            | Per-metric summaries: min, max, mean, last value, last step.                                                                        |
| `pluto.query.get_files(project, run_id, file_name=None)`                                    | Files logged on the run, optionally filtered by name.                                                                               |
| `pluto.query.download_file(project, run_id, file_name)`                                     | Stream a single file to local disk.                                                                                                 |
| `pluto.query.get_logs(project, run_id, log_type=None)`                                      | Console logs (stdout/stderr) with optional cursor-based paging.                                                                     |
| `pluto.query.compare_runs(project, run_ids, metric_name)`                                   | A single metric across many runs side-by-side.                                                                                      |
| `pluto.query.leaderboard(project, metric_name, ...)`                                        | Rank runs in a project by a single metric.                                                                                          |

All helpers raise on the network or auth error path; otherwise they return parsed Python objects. Authentication is resolved from `PLUTO_API_KEY` or your saved login.

## Filtering runs

<Note>
  The API for `filters` is currently in preview. The API may change at any moment. Check in frequently for updates. Have feedback? Let's get in touch at [founders@trainy.ai](mailto:founders@trainy.ai)
</Note>

`list_runs` accepts a `filters` argument with a query language. It composes boolean logic (`$and` / `$or` / `$not`) over conditions over run configurations/status/staleness. Consider the following example that checks for runs that haven't `COMPLETED` and haven't reported any metrics in the past hour.

```python theme={null}
import pluto
from datetime import datetime, timedelta, timezone

# An ISO-8601 timestamp one hour ago — the "stale" boundary.
cutoff = (datetime.now(timezone.utc) - timedelta(hours=1)).strftime("%Y-%m-%dT%H:%M:%SZ")

# Find interrupted jobs to retry: not finished, and no data in the last hour.
stale = pluto.query.list_runs("my-project", filters={"$and": [
    {"status": {"$ne": "COMPLETED"}},
    {"heartbeat_at": {"$lt": cutoff}},
]})
```

### Operators

| Operator                     | Meaning                                                                             |
| ---------------------------- | ----------------------------------------------------------------------------------- |
| `$and`, `$or`, `$not`        | Combine conditions. Multiple keys in one object are implicitly ANDed.               |
| *(bare value)*, `$eq`        | Equals — `{"status": "RUNNING"}` is shorthand for `{"status": {"$eq": "RUNNING"}}`. |
| `$ne`                        | Not equal.                                                                          |
| `$gt`, `$gte`, `$lt`, `$lte` | Numeric / timestamp comparison. Put two on one field for a range.                   |
| `$in`, `$nin`                | Value is in / not in a list.                                                        |
| `$regex`                     | Regular-expression match (text fields).                                             |

### Fields

| Field                      | Notes                                                                                                                                                   |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `state` / `status`         | Lifecycle: `RUNNING`, `COMPLETED`, `FAILED`, `TERMINATED`, `CANCELLED`                                                                                  |
| `heartbeat_at`             | Last time the run reported data (ISO-8601). `$gte` = active since; `$lt` = stale before. A run that never logged data has no heartbeat and won't match. |
| `created_at`, `updated_at` | Run timestamps (ISO-8601).                                                                                                                              |
| `name`                     | Run name (supports `$regex`).                                                                                                                           |
| `tags`                     | Run tags (`$in` = has any of these).                                                                                                                    |
| `config.<key>`             | Any value from the run's config, e.g. `config.lr`, `config.model`.                                                                                      |
| `systemMetadata.<key>`     | Any value from the run's captured environment, e.g. `systemMetadata.gpu_model`, `systemMetadata.cuda_version`, `systemMetadata.git_branch`.             |
| `summaryMetrics.<key>`     | A metric's last value, e.g. `summaryMetrics.val_acc`.                                                                                                   |

### More examples

```python theme={null}
import pluto
from datetime import datetime, timedelta, timezone

# An ISO-8601 timestamp one hour ago — the "stale" boundary.
cutoff = (datetime.now(timezone.utc) - timedelta(hours=1)).strftime("%Y-%m-%dT%H:%M:%SZ")

# Hyperparameter slice
pluto.query.list_runs("my-project", filters={"config.lr": {"$gt": 0.001}, "config.model": "gpt"})

# Top performers by a summary metric (latest reported)
pluto.query.list_runs("my-project", filters={"summaryMetrics.val_acc": {"$gte": 0.9}})

# Slice by the captured environment — e.g. only the H100 runs off a given branch
pluto.query.list_runs("my-project", filters={
    "systemMetadata.gpu_model": "H100",
    "systemMetadata.git_branch": "main",
})

# running OR reported data in the last hour
pluto.query.list_runs("my-project", filters={"$or": [
    {"state": "running"},
    {"heartbeat_at": {"$gte": cutoff}},
]})

# stale, but active within the last day — a heartbeat range on one field
day_ago = (datetime.now(timezone.utc) - timedelta(days=1)).strftime("%Y-%m-%dT%H:%M:%SZ")
pluto.query.list_runs("my-project", filters={"$and": [
    {"status": {"$ne": "COMPLETED"}},
    {"heartbeat_at": {"$gte": day_ago, "$lt": cutoff}},
]})
```

`filters` AND-combines with `search`, `tags`, and `sort` on the same call, and pages with `limit` / `offset`.

<Warning>
  Filtering on `heartbeat_at` or `summaryMetrics.*`, and any `$or` / `$not`, require a `project` (they're scoped to a single project). Unknown fields or operators return a `400`.
</Warning>
