Query runs, metrics, and objects

Use the SDK query API for bounded notebook and automation reads.

Open .md

Use im.Api(...) when a script or notebook needs to query runs, fetch bounded metric series, inspect logged objects, or download artifacts — everything a training script's write path does not cover.

Prerequisites

  • An API key with a read scope such as export:read for tenant read routes.

Create an API helper

python
import instantml as im

api = im.Api(
    base_url="https://api.instantml.ai",
    api_key="instantml_...",
)

Query run summaries

python
runs = api.query_runs(
    project="cartpole",
    q="tag:baseline status:finished",
    sort_by="metric-best",
    metric_key="eval/return_mean",
    limit=25,
)

for run in runs.items:
    print(run["id"], run.get("name"))

Accepted filters:

ParameterMeaning
projectProject name. Omit or use all for all projects.
statusrunning, finished, failed, or all.
qShared run search query. Bare text remains implicit AND; field filters, exact tags/status, ID prefixes, uppercase booleans, phrases, grouping, field/group exclusion such as -tag:debug, and explicit Rust re:/.../ regex are supported.
sort_bycreated, name, status, duration, metric-latest, or metric-best.
metric_keyMetric used for metric sorts.
limitPage size, 1..100.
cursorCursor returned by the previous Page.
max_pagesNumber of pages to read into one Page; defaults to 1.

query_runs() returns Page(items, next_cursor, raw, limit) and preserves the server's order exactly. Use iter_runs() when you want lazy pagination:

python
for run in api.iter_runs(project="cartpole", q="tag:candidate", page_size=50, max_pages=2):
    print(run["id"])

Useful q examples:

text
seed 13
tag:baseline status:finished
name:"long context" -tag:debug
(tag:baseline OR tag:candidate) notes:ablated
re:/seed-(13|14)/

Fetch metric series

python
series = api.query_metrics(
    [run["id"] for run in runs.items],
    ["eval/return_mean", "train/loss"],
    step_min=0,
    step_max=1000,
    point_limit=1000,
    buckets=400,
)

for item in series.series:
    print(item["run_id"], item["key"], len(item["metrics"]))

query_metrics() accepts 1..100 run IDs and 1..25 keys. The SDK calls the bounded metric-series route once per key, preserves caller run and key order, omits empty run/key pairs, and keeps each run/key bounded by point_limit before server-side effective caps. buckets requests the same M4 downsampling used by high-density dashboard charts.

Metric timestamp windows are not exposed by the current API route. The SDK accepts the future-facing parameters but raises ValueError if time_min, time_max, or x_axis="time" are used, so notebooks do not silently receive a different slice than requested.

Query rich objects

python
objects = api.query_objects(
    project="cartpole",
    kind="table",
    key="eval/samples",
    limit=25,
)

rows = api.object_rows(objects.items[0]["id"], limit=100)

query_objects() uses the cross-run GET /api/objects/explorer route when the backend exposes it. On older backends it falls back only when you pass a single run_id:

python
objects = api.query_objects(run_id="run-id", kind="table", key="eval/samples")

The SDK does not emulate cross-run object search by paging every matching run. That keeps notebook code from accidentally turning a small query into an unbounded fan-out.

Download artifact bytes

python
path = api.download_artifact(
    "artifact-id",
    "checkpoints/policy.pt",
)
print(path)

The helper creates parent directories and returns the written path. It is the same restore primitive used by checkpoint resume snippets in the dashboard.

Stay inside read bounds

InstantML keeps list and series reads bounded:

  • Run summary and rich-object pages default to 100 rows.
  • Raw metric history is requested through metric-specific series endpoints.
  • Metric query inputs are capped at 100 run IDs and 25 metric keys.
  • Table row reads are capped at 1,000 rows per request.
  • Artifact lists are capped.
  • Export responses include truncation metadata when limits are hit.

If you need a bulk data movement path, use export or an importer/exporter flow instead of repeatedly fetching every chart series from a notebook.

Write to an existing run

Use im.attach_run(...) when a resume script should continue logging into an existing run, such as a checkpoint fork created by the dashboard or Api.fork_run(...).

python
run = im.attach_run("child-run-id")
run.log({"train/loss": 0.1}, step=1001)
run.finish()

By default, attach_run(validate=True) reads /runs/:id before returning a run handle. That validation needs read access such as export:read. Use validate=False only for intentionally write-only credentials or offline attach flows.

Next steps