---
title: Runner lifecycle
description: One machine, one job, one Sandboxes lease — the five states a runner moves through, and the typed reasons it can fail with.
type: explanation
product: runners
summary: What a runner is between being leased and being wiped.
updated: 2026-10-01
order: 1
---

<Callout tone="note" title="Today this runs on the management API">
Your runners are listed with `GET /v1/runners`, which shows each `status`, and a runner's jobs with `GET /v1/runners/{id}/jobs`; see the [Runners quickstart](/docs/runners/quickstart). The `runners get` and `runners list` calls below are not served at api.sylphx.com.
</Callout>

A Runner is one runner: one machine for exactly one job, on its own Sandboxes
lease, released and wiped after. It is the smallest unit in the product, and
it is disposable by design — a runner that has finished a job has no further
use for anything the job left behind, so nothing is kept.

Runners is its only writer. A caller reads a runner to find out what ran, when
and how it ended; nothing on the caller's side creates one or pushes work onto
one.

## The five states

`state` is the lifecycle state, and it is observed rather than set:

| State | What it means |
| --- | --- |
| `provisioning` | The machine is being leased and made ready. No job has started. |
| `idle` | The machine is waiting for a job. |
| `busy` | The machine is running a job. |
| `finished` | The job ended. |
| `failed` | It never ran a job. |

The two middle states are the ones a scale set reports as counters — runners
running a job and runners waiting for a job — so `busy` and `idle` are the
same fact read at the runner and at the registration. `finished` is a job that
ran; `failed` is a job that never did.

## Why a runner never ran a job

When `state` is `failed`, `failure` says why in one typed word:

| Reason | What it means |
| --- | --- |
| `no_capacity` | No capacity could be leased for it. |
| `class_not_offered` | Its class is not offered where it had to run. |
| `capability_missing` | A capability its class needs is missing. |
| `boot_failed` | Its machine did not finish booting. |

The reason is an enum rather than a message, and it is about the machine
rather than about the work: `failure` is set only when the runner never ran a
job, so a runner that ran one ends `finished`.

## What the record carries

A runner is a record of one job, and the fields are read-only:

<PropertyTable
	properties={[
		{
			name: 'state',
			type: 'RunnerState',
			description: 'The lifecycle state. One of provisioning, idle, busy, finished, failed.',
		},
		{
			name: 'failure',
			type: 'RunnerFailure',
			description: 'Why it never ran a job, when state is FAILED. One of no_capacity, class_not_offered, capability_missing, boot_failed.',
		},
		{
			name: 'runner_class',
			type: 'string',
			description: 'The class it runs as.',
		},
		{
			name: 'lease',
			type: 'string',
			description: 'Its Sandboxes lease.',
		},
		{
			name: 'repository',
			type: 'string',
			description: 'The repository of its job, owner/name.',
		},
		{
			name: 'job_uri',
			type: 'string',
			description: 'The job on the forge.',
		},
		{
			name: 'start_time',
			type: 'timestamp',
			description: 'When its job started.',
		},
		{
			name: 'end_time',
			type: 'timestamp',
			description: 'When its job ended.',
		},
	]}
/>

`lease` is the link to the machine underneath: the Sandboxes lease is what the
job actually ran on, and it is released and wiped when the job ends. The
`repository` and `job_uri` pair is the link back to the forge, which is where
the job's own logs and result live.

## Reading one

A runner is read by name, and its name sits under the scale set that produced
it:

```bash
sylphx runners runners get orgs/acme/scale_sets/scale-set/runners/runner
```

```bash
curl "https://api.sylphx.com/v1/orgs/acme/scale_sets/scale-set/runners/runner" \
  -H "Authorization: Bearer $SYLPHX_API_KEY"
```

```ts
const response = await sylphx.runners.runners.get({ name: 'orgs/acme/scale_sets/scale-set/runners/runner' })
```

The parent is the scale set, so listing a scale set's runners is the way to
read what it has done:

```bash
sylphx runners runners list orgs/acme/scale_sets/scale-set
```

Both reads need `runners:read`. Every method, its scope and its examples are in
[the runners reference](/docs/api/runners).

<RelatedDocs
	links={[
		{
			href: '/docs/runners/scale-sets',
			label: 'Scale sets',
			description: 'The registration these runners belong to.',
		},
		{
			href: '/docs/api/runners',
			label: 'The runners collection',
			description: 'The two reads, their scope and their examples.',
		},
		{
			href: '/docs/runners/quickstart',
			label: 'Quickstart',
			description: 'Register a scale set and read its runners back.',
		},
	]}
/>
