Skip to content

List your runs (newest first)

GET
/v1/runs
curl --request GET \
--url 'https://beta-api.plune.ai/v1/runs?limit=50&offset=0' \
--header 'Authorization: Bearer <token>'

The Runs screen (api.ts → listRuns) and the first call to make with a fresh token. Summaries, not full runs: identity, the headline counts, cost and duration, the eval score with its movement against the previous finished run of the same environment. Offset paging — a run list is short enough for it; the audit feed, which is not, pages by cursor.

limit
integer
default: 50 >= 1 <= 200
offset
integer
0
environment
string

Only runs that declared this environment. Blank or absent means every run — a caller building the query from an unset CI variable asks for everything, not for the empty string.

planId
string

Only runs launched from this plan (meta.planId, D33) — the «Runs of this plan» list. Blank or absent means every run.

q
string

Only runs whose title contains this text, in any case — the search palette (#866). Text, not a pattern: % and _ match themselves, as in the cases list. A run without a title is not found by one. Blank or absent means every run.

key
string

Only the run that carries this externalKey, whole — the key a reporter joins by (PLUNE_RUN=<key>), so plune run grep <key> finds its run (plune-ai/cli#85). At most one: a key belongs to one live run of the project. Blank or absent means every run.

custom
Array<string>

<fieldId>:<value> (#1766, ADR 0048): only the runs whose custom field holds the value — the text of a string field, the option id of a list (a multiple list matches when it holds it), the number of a number field. Repeat for one field to OR its values; different fields are AND-ed. A field or a value nobody holds matches nothing; a pair without a field or a value is a 400 that names the form.

Your runs

Media type application/json
object
runs
required
Array<object>

A run as it appears in the list — identity + the headline numbers, derived from the run.

object
id
required
string format: uuid
createdAt
required
string format: date-time
kind
required

What kind of run this is. eval for a plune sync upload, automated for a CI report or a Cairn ingest, otherwise whatever the lifecycle start declared.

string
Allowed values: automated manual mixed eval
title

What the run is called, or null while nobody has said.

string
nullable
environment

Where it ran, or null while nobody has said.

string
nullable
labels

How the run is marked. Empty when unmarked.

Array<string>
source
required

Where the run came from. cairn is an INGEST rather than an eval run: it groups the Results a Cairn run produced. total/passed/failed are counted from those Results and are real numbers. costUsd and durationMs are always 0 and mean “not applicable”: Cairn neither prices a run nor times one. cli covers BOTH a run uploaded by plune sync and one started through the run lifecycle — read measured to tell those apart, since only the first carries a cost and a duration.

string
Allowed values: cli cairn
total
required
integer
passed
required
integer
failed
required

Results whose status is failed — by name, not total − passed: a skipped test is not a failure. For an eval run, the summary’s own failed, less the failed rows of muted cases (muted).

integer
broken
required

Results whose status is broken. Always 0 for an eval run.

integer
blocked
required

Results whose status is blocked. Always 0 for an eval run.

integer
skipped
required

Results whose status is skipped. Always 0 for an eval run.

integer
muted
required

Failures of muted cases, out of failed and broken and still in total. A failed or broken result of a muted case is counted as muted, not as a failure; a finished run never changes (#1247). For an eval run, in the summary’s rows: the failed and errored rows of a muted case’s eval.

integer
costUsd
required
number
durationMs
required
integer
measured
required

Whether costUsd and durationMs are measurements or absences — otherwise both are the same 0. Do NOT re-derive this from source: a run started through the run lifecycle (POST /v1/runs with schemaVersion: 2) reports cli, because it did come from a client, and carries neither. Only a run uploaded by plune sync does.

boolean
running
required

Whether the run is under way — true while the status is launched or rerun, false once it is finished or terminated, and for a scheduled run that waits for Launch (#1233). Read this rather than deriving a verdict from the counts: a run that has just started has failed: 0 like a run that passed, and the two mean opposite things. A plune sync upload and a Cairn ingest both record a run that has already ended, so both are always false.

boolean
score
required

An eval run’s one number: passed / total in whole points out of 100. Null for every other kind, and for an eval run that ran nothing — a score of nothing is absent, not 0.

integer
nullable <= 100
scheduledCases

How many cases a scheduled run will expect (#1233) — the list’s «scheduled · 12 cases», since nothing has run. null for every other run.

integer
nullable
scoreDelta
required

score minus the score of the previous finished eval run in the same environment (a null environment compares with null), or null when there is none. Null means “no comparison”, not “no change”. Same environment rather than same externalKey: the key would compare a nightly against a pull request, and an eval run has none.

integer
nullable
total

How many runs the same filters match in all — not the page, and not what is in the Bin. What «Select all N runs» says (#1100).

integer
Example
{
"runs": [
{
"id": "6f1c2b3a-0000-4000-8000-0000000000d1",
"createdAt": "2026-09-16T09:12:04.151Z",
"kind": "automated",
"source": "cli",
"title": "plune · 2026-09-16 09:12 · ci",
"environment": "staging",
"labels": [
"plune",
"vitest",
"ci"
],
"total": 2,
"passed": 1,
"failed": 1,
"broken": 0,
"blocked": 0,
"skipped": 0,
"muted": 0,
"score": null,
"scoreDelta": null,
"costUsd": 0,
"durationMs": 4931,
"measured": false,
"running": false
}
],
"total": 1
}

No / invalid token or session