# Machines

> What a machine is: its states, its sizes, how it sleeps when idle, copies, snapshots, names, labels, projects, where it runs and what it costs.

A machine is a Linux computer of your own, reached through the API. It runs your commands and keeps your files, and it is charged by the second while it runs.

wm:

```sh
$ wm machines create --name trainer --cpus 8 --label team=ml --idle-after 30m
ID                            NAME     STATE    SIZE          LOCATION      AGE
m_01jb2xk3n4p5q6r7s8t9v0w1x2  trainer  running  8 CPU, 16 GB  Helsinki, FI  0s
```

Python:

```python
machine = client.machines.create(
    name="trainer", cpus=8, labels={"team": "ml"}, idle_after_s=1800
)
print(machine.id, machine.state)
```

TypeScript:

```ts
const machine = await client.machines.create({
  name: "trainer", cpus: 8, labels: { team: "ml" }, idle_after_s: 1800,
});
console.log(machine.id, machine.state);
```

curl:

```sh
curl -X POST https://api.wheelmachine.ai/v1/machines \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "trainer", "cpus": 8, "labels": {"team": "ml"}, "idle_after_s": 1800}'
```

## States

Starting becomes running. From running, `pause`, `stop` and `archive` put a machine away, each keeping more or less of it; `start` brings it back. `delete` ends it from any state.

**starting**

Being made ready. When no server has room at once, one is made ready for it: the answer is `202`, and [a wait](https://docs.wheelmachine.ai/machines.html#wait-for-it) follows it until it runs.

**running**

It runs; commands and files work. Charged by the second.

**paused**

Its memory is kept and nothing runs; no running time is charged. A command wakes it, and so does `start`: it carries on where it was.

**stopped**

Its files are kept, its memory is not. `start` runs it again from its files.

**archived**

Its files are put away in storage: the cheapest way to keep a machine. `start` brings it back.

**recovering**

Its server was lost, and it is being brought back from its last moments. Wait for `running`.

**deleted**

Gone, with its files. Deleting cannot be undone.

| To | wm | API |
|---|---|---|
| Pause it | `wm machines pause <machine>` | `POST /v1/machines/{machine_id}/pause` |
| Run it again | `wm machines start <machine>` | `POST /v1/machines/{machine_id}/start` |
| Stop it | `wm machines stop <machine>` | `POST /v1/machines/{machine_id}/stop` |
| Archive it | `wm machines archive <machine>` | `POST /v1/machines/{machine_id}/archive` |
| Delete it | `wm machines rm <machine>` | `DELETE /v1/machines/{machine_id}` |

A move its state does not allow, such as pausing a machine that is not running, answers [`409 conflict`](https://docs.wheelmachine.ai/errors/conflict.html).

## Sizes

A machine has 2, 4, 8 or 16 CPUs, with 2 GB of memory for each. It is charged by the second at the 2-CPU price that many times over: a 16-CPU machine costs eight times a 2-CPU one.

| CPUs | Memory | wm | API |
|---|---|---|---|
| 2 (when not said) | 4 GB | `--cpus 2` | `"cpus": 2` |
| 4 | 8 GB | `--cpus 4` | `"cpus": 4` |
| 8 | 16 GB | `--cpus 8` | `"cpus": 8` |
| 16 | 32 GB | `--cpus 16` | `"cpus": 16` |

The size is chosen when the machine is made, and a copy has its original's size.

> **Coming:** Machines with a GPU. They are not open to every account yet; `wm gpus` shows what is coming.

## Sleep when idle

A machine pauses by itself once it is idle: nothing has reached it for `idle_after_s` seconds (300, five minutes, when not said), and its programs have been quiet as long, under 5% of one CPU on average. A job left working keeps it awake. Paused, it keeps its memory and no running time is charged; the next command wakes it.

wm:

```sh
$ wm machines create --name nightly --idle-after 2h     # 1m to 24h
$ wm machines create --name server --no-sleep           # never pauses by itself
```

API:

```json
{"name": "nightly", "idle_after_s": 7200}
{"name": "server", "sleep_when_idle": false}
```

`idle_after_s` is 60 to 86400 seconds. A machine made with `sleep_when_idle` false never pauses by itself: it runs, and is charged, until it is paused or stopped. Both are set when the machine is made; a copy sleeps as its original does. The machine says how it sleeps in `sleep_when_idle` and `idle_after_s` (null when it never does).

## Wait for it

Making, starting or copying a machine answers once it runs, usually in well under a second. When no server has room just now, one is made ready for it; if that takes longer than `wait_s` (60 seconds when not said, at most 600), the answer is `202` with the machine `starting`, and a wait follows it:

wm:

```sh
$ wm machines wait box                     # until it runs, for up to 10 minutes
$ wm machines wait box --state paused --timeout 2m
```

Python:

```python
machine = client.machines.wait(machine.id, "running", timeout_s=600)
```

TypeScript:

```ts
const ready = await client.machines.wait(machine.id, "running", { timeout_s: 600 });
```

curl:

```sh
curl "https://api.wheelmachine.ai/v1/machines/m_01jb2xk3n4p5q6r7s8t9v0w1x2/wait?state=running&timeout_s=120" \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY"
```

One wait call lasts at most 600 seconds; a machine not there by then answers [`408 timeout`](https://docs.wheelmachine.ai/errors/timeout.html), and you can wait again. `wm` and the libraries wait for you; `wm machines create --no-wait` answers at once instead.

## Copies

Terminal:

```sh
$ wm machines copy box --name box-2
ID                            NAME   STATE    SIZE         LOCATION      AGE
m_01jb2xm7c9d4e8f2g6h1j5k3n0  box-2  running  2 CPU, 4 GB  Helsinki, FI  0s
```

A copy is a new machine, made from the original as it is now, files and all, beside it where there is room, so its files are copied in a moment. It has the original's name and labels unless you give others (`--label` gives the copy its own labels in place of the original's), and the original's size and sleep. From then on it is a machine of its own: charged, paused and deleted on its own.

## Snapshots

Terminal:

```sh
$ wm machines snapshot box --note "before the upgrade"
SNAPSHOT                   MACHINE                       NOTE                MADE
20261023T093500Z-3f2a0001  m_01jb2xk3n4p5q6r7s8t9v0w1x2  before the upgrade  2026-10-23 09:35 UTC
$ wm machines create --name box-again --from-snapshot box:20261023T093500Z-3f2a0001
```

A snapshot keeps the machine's files as they are now. A new machine made `from_snapshot` starts with those files; give the machine alone (`--from-snapshot box`) for its latest snapshot. Keep a snapshot's id when it is made: the API does not list them.

## Names and labels

A machine's id is made by the API: `m_` and 26 letters and digits. Its name is for people, up to 80 characters. `wm` takes a name wherever it takes an id; when two machines share a name, give the id.

Terminal:

```sh
$ wm machines label box team=ml stage=test    # set two labels
$ wm machines label box stage-                # take one off
$ wm machines ls --label team=ml              # machines with that label
$ wm machines rename box trainer
```

A machine holds up to 32 labels. A label's name begins with a letter or a digit and goes on with letters, digits, `.`, `_`, `-` and `/`, up to 63 of them; its value is up to 200 characters. Through the API, labels given to `PATCH /v1/machines/{machine_id}` merge with the ones there, and a label given `null` is taken off.

## Projects

Every machine is in a project. An account starts with one, and machines go there unless another is named.

Terminal:

```sh
$ wm projects create research
$ wm machines create --name box --project research
$ wm machines ls --project research
```

A key can be limited to some projects, so a program sees only its own machines: see [Keys for some projects](https://docs.wheelmachine.ai/keys.html#keys-for-some-projects). A project can be deleted only once it holds no machines.

## Where it runs

`--region` (`region` in the API) asks for a machine near a place: an id from `wm regions`. It runs near there, wherever there is room soonest, and says where it actually runs in its `location`.

## Running time and money

A machine is charged by the second while it runs. `running_seconds` is all the time it has run, and `wm usage` (`GET /v1/usage`) says what each machine ran for and cost in a month:

Terminal:

```sh
$ wm usage --month 2026-10
MACHINE                       PROJECT                         RAN     COST
m_01jb2xk3n4p5q6r7s8t9v0w1x2  prj_01jb2xk3n4p5q6r7s8t9v0w1x2  1h 38m  $0.1312
total 2026-10                 -                               -       $0.1312
```

When the account cannot spend - its limit for the month is reached, or the account is held - its running machines are paused within about half a minute, with their memory kept, and making or starting machines, running commands and reaching files answer [`402 payment_required`](https://docs.wheelmachine.ai/errors/payment_required.html) until it can again. `wm me` says whether the account can spend.

## Delete

`wm machines rm box` asks first; `--yes` does not. Deleting takes the machine's files with it and cannot be undone. Deleting a machine that is already deleted is not an error.

## What a machine says about itself

GET /v1/machines/{machine_id}:

```json
{
  "id": "m_01jb2xk3n4p5q6r7s8t9v0w1x2",
  "object": "machine",
  "name": "trainer",
  "project": "prj_01jb2xk3n4p5q6r7s8t9v0w1x2",
  "state": "running",
  "gpu": null,
  "size": {"cpus": 8, "memory_gb": 16},
  "location": {"city": "Helsinki", "country": "FI"},
  "cpus": 8,
  "memory_gb": 16,
  "sleep_when_idle": true,
  "idle_after_s": 1800,
  "labels": {"team": "ml"},
  "network": {"internet": "open", "allow": []},
  "files_sealed": true,
  "running_seconds": 5904.2,
  "cpu_cores": 6.4,
  "memory_bytes": 9126805504,
  "created_at": "2026-10-23T09:30:00Z",
  "last_used_at": "2026-10-23T11:08:24Z"
}
```

Every field is in the reference: [Machine](https://docs.wheelmachine.ai/reference.html#obj-Machine).
