Creating runs
A run is created once, by name, and then written to by as many processes as you like. There are two ways to create one:
CreateRun(gRPC orPOST /api/ingest/v1/runs) creates the run and fails if it already exists. Pair it withUpdateRuns.InitializeRunLogging(gRPC only) creates the run or attaches to an existing one, and registers the caller as a streaming logger. See Streaming ingestion.
Both take the same Run definition, create_project_if_missing flag and
aggregation_rules.
The run definition
Section titled “The run definition”{ "run": { "workspace": "my-workspace", "organization": "my-org", "project": "vision", "runName": "resnet50-lr3e-4", "experiment": "lr-sweep", "directory": "sweeps/2026-09", "creationTime": "2026-09-30T09:00:00Z", "orchestrationIdentifier": "slurm-8812345" }, "createProjectIfMissing": true}| Field | Notes |
|---|---|
workspace |
Must exist. Your token needs member access to it. |
organization |
Optional organization slug; needed only when another organization has a workspace of the same name. |
project |
Created if missing when createProjectIfMissing is true; otherwise a missing project is NOT_FOUND (404). |
runName |
Unique within the project. |
experiment |
Optional. Created on first use. A run’s experiment cannot be changed later. |
directory |
Optional /-separated folder path the run is placed in; missing folders are created. The run can be moved later. |
expDirectory |
Optional folder for the experiment, used only when this call creates the experiment. Defaults to directory. |
creationTime |
Optional; defaults to the time of the call. |
forkPoint |
Optional; see Forking. |
orchestrationIdentifier |
Optional opaque token for the job launch that created the run; see below. |
Project names, run names and environment ids appear in portal URLs, so they follow the strictest rules:
- Not empty, at most 512 bytes, and not starting with
:. - No whitespace or control characters.
- None of
( ) [ ] , = < > ! ~ " |— reserved by the query language. - None of
/ \ ? # %— they have meaning in a URL. - Not a name reserved for a portal route.
Anything else is allowed, including Unicode. Metric names, scales and attribute paths follow the same rules
except that / is allowed (it builds hierarchies such as train/loss); see Limits.
Conflicts
Section titled “Conflicts”CreateRun is strict: if a run with the same name already exists in the project, it fails with ALREADY_EXISTS.
Over REST that is a 409 with a JSON body describing the existing run:
{ "message": "Run already exists: my-workspace/vision/resnet50-lr3e-4", "creation_time": "2026-09-30T09:00:00+00:00", "orchestration_identifier": "slurm-8812345"}(These keys are snake_case, unlike the camelCase message JSON.) creation_time may be null, and
orchestration_identifier is null when the existing run was created without one.
A 409 after a retry is usually good news: the first attempt created the run and only its response was lost.
Compare orchestration_identifier with your own to tell that case — or a sibling process of the same job winning
the race — from a stale run left by an earlier job that reused the name.
Orchestration identifiers
Section titled “Orchestration identifiers”When several processes of one job write to the same run (for example, ranks of a distributed training job), give
them all the same orchestrationIdentifier — typically the scheduler’s job id — and give each new job launch a
different one. Metrana stores the identifier of the creating request and never interprets it; it is up to 256
bytes of any printable text.
InitializeRunLogging uses it to decide whether an existing run may be attached to; see
Resuming an existing run.
Forking
Section titled “Forking”A fork starts a new run from a point in an existing one: everything the parent logged up to and including
forkStep is carried into the child, which then continues on its own.
{ "run": { "workspace": "my-workspace", "project": "vision", "runName": "resnet50-lr1e-4-from-20k", "forkPoint": {"parentRunName": "resnet50-lr3e-4", "forkStep": "20000"} }}The parent must be in the same project; a missing parent is NOT_FOUND. For reinforcement-learning series,
forkStep is matched against the RL step. The carried-over history is copied asynchronously: you can write to the
child immediately, and the inherited points appear shortly after.
Aggregation rules
Section titled “Aggregation rules”aggregationRules declare derived series that Metrana computes while ingesting, for example the mean of a metric
across every GPU. They are registered when the run is created. See
Aggregation rules.
After creation
Section titled “After creation”Write to the run with UpdateRuns or a
stream. A run is running while writers are active, closed once every writer
has sent closeRun, and marked crashed if its writers go quiet for a long time without closing (15 minutes by
default).