# Command line

> The wm command: install it, log in, and every command and flag for machines, commands, files, projects, keys and the catalogue.

`wm` drives Wheelmachine from a terminal: machines, commands, files, projects and keys. Every command answers `-h` with its flags.

Terminal:

```sh
$ wm login
$ wm machines create --name box --cpus 4
$ wm exec box -- make test
$ wm cp box:work/report.html .
$ wm machines rm --yes box
```

## Install

For now `wm` is built from its source, with Go 1.27 or later (an older `go` fetches 1.27 by itself). It is one file, with nothing else to install, and the same build gives `wm-mcp`, the server for [agents](https://docs.wheelmachine.ai/agents.html):

Terminal:

```sh
$ cd frontend/cli
$ go build -o bin/ ./cmd/...      # writes bin/wm and bin/wm-mcp
$ go install ./cmd/...            # or puts them in $(go env GOPATH)/bin
$ wm --version
wm 1.0.0
```

## Log in

`wm login` signs you in through your browser, with GitHub or Google: it shows a short code and opens `https://app.wheelmachine.ai/device`, where you sign in, type the code and approve. `wm` is then given a key of its own, named for this computer (`"wm on laptop"`, say), checks it with the API and keeps it in `~/.config/wheelmachine/config.json` (under `$XDG_CONFIG_HOME` when that is set), in a file only you can read. On a computer with no browser, open the address on any other device. To keep a key you already have, `wm login --key` asks for it without showing it as you type, or reads it from standard input: `wm login --key < keyfile`.

| Variable | What it does |
|---|---|
| `WHEELMACHINE_API_KEY` | The key to use. When set, it is used before the one `wm login` kept. |
| `WHEELMACHINE_BASE_URL` | Where the API is; `https://api.wheelmachine.ai` when not set. |
| `XDG_CONFIG_HOME` | Where `wm login` keeps the key, in `wheelmachine/config.json`. |

## The basics

- **Names.** A machine is named by its id (`m_...`) or its name, a project by its id (`prj_...`) or its name, and a key by its id (`key_...`) or its name. When two share a name, give the id.
- **Output.** Tables for people. `--json` prints the API's own JSON, and `-q` (`--quiet`) prints ids only, one a line, for scripts. Both go on any command.
- **Asking first.** `wm machines rm` and `wm keys revoke` ask before they act; away from a terminal they need `--yes`.
- **Trying again.** A call refused for a moment (too many calls, no room just now) is tried again after the wait the API asks for, and `wm` says so at a terminal. A command run in a machine is never sent twice.

## Exit codes

| Code | When |
|---|---|
| 0 | Done. |
| 1 | The API or the network refused. `wm` prints why, with the refusal's code and request id. |
| 2 | The command was not right: a missing word, a flag that does not exist. |
| Any | `wm exec` and `wm sh` exit with the command's own exit code (255 for one outside 0 to 255). |
| 130 | Stopped with Ctrl-C. |

## Machines

### wm machines ls

`wm machines ls [flags]`

List machines, newest first.

| Flag | What it does |
|---|---|
| `--project <project>` | Only this project's machines. |
| `--state <state>` | Only machines in this state: `starting`, `running`, `paused`, `stopped`, `archived` or `recovering`. |
| `--label key=value` | Only machines with this label; repeat for more. |
| `--limit <n>` | Show at most this many (0, the default: all). |

### wm machines create

`wm machines create [flags]`

Make a machine. It answers once the machine runs, usually in well under a second; when a server has to be made ready for it first, `wm` waits for it, up to `--timeout`.

| Flag | What it does |
|---|---|
| `--name <name>` | A name for people; ids are made by the API. |
| `--project <project>` | Its project; the account's first when left out. |
| `--cpus <n>` | Its CPUs: 2, 4, 8 or 16, with 2 GB of memory each; 2 when left out. |
| `--region <region>` | A place to run near, from `wm regions`. |
| `--label key=value` | A label; repeat for more. |
| `--from-snapshot machine[:snapshot]` | Start from a snapshot's files: the machine's latest when no snapshot is named. |
| `--idle-after <duration>` | Pause by itself once nothing has reached it, and its programs have been quiet, this long: `1m` to `24h`; `5m` when left out. |
| `--no-sleep` | Never pause by itself: it runs, and is charged, until it is paused or stopped. |
| `--timeout <duration>` | How long to wait for it to run; `10m` when left out. |
| `--no-wait` | Answer at once, while it may still be starting. |
| `--gpu <gpu>` | **Coming:** A GPU to give it, from `wm gpus`. Not open to every account yet. |

### wm machines get

`wm machines get <machine>`

Show one machine: its state, size, where it runs, how it pauses, its labels, its running time and what it uses now.

Terminal:

```sh
$ wm machines get box
id:               m_01jb2xk3n4p5q6r7s8t9v0w1x2
name:             box
state:            running
project:          prj_01jb2xk3n4p5q6r7s8t9v0w1x2
size:             2 CPU, 4 GB memory
location:         Helsinki, FI
pauses:           after 5m 00s idle (nothing reached it, its programs quiet)
labels:           team=ml
files sealed:     yes
running time:     42m 10s
processors used:  0.12
memory used:      612.4 MiB
created:          2026-10-23 09:30 UTC (42m ago)
last used:        2026-10-23 10:11 UTC (1m ago)
```

### wm machines rm

`wm machines rm [--yes] <machine>...`

Delete machines and all their files. This cannot be undone.

| Flag | What it does |
|---|---|
| `-y`, `--yes` | Delete without being asked. |

### wm machines pause

`wm machines pause <machine>...`

Pause machines with their memory kept: nothing runs and no running time is charged. `start` brings them back where they were.

### wm machines start

`wm machines start <machine>...`

Run machines again, from paused, stopped or archived.

| Flag | What it does |
|---|---|
| `--timeout <duration>` | How long to wait for each to run; `10m` when left out. |
| `--no-wait` | Answer at once, while it may still be starting. |

### wm machines stop

`wm machines stop <machine>...`

Stop machines: their files stay, their memory does not.

### wm machines archive

`wm machines archive <machine>...`

Put machines' files away in storage, the cheapest way to keep them. `start` brings them back.

### wm machines copy

`wm machines copy <machine> [flags]`

Make a new machine, a copy of this one as it is now, beside it where there is room. Its name and labels are the original's unless given.

| Flag | What it does |
|---|---|
| `--name <name>` | The copy's name. |
| `--label key=value` | A label for the copy, in place of the original's; repeat for more. |
| `--timeout <duration>` | How long to wait for it to run; `10m` when left out. |
| `--no-wait` | Answer at once, while it may still be starting. |

### wm machines snapshot

`wm machines snapshot <machine> [--note <words>]`

Keep a machine's files as they are now. Make a machine from it with `wm machines create --from-snapshot <machine>:<snapshot>`.

| Flag | What it does |
|---|---|
| `--note <words>` | A note to know it by, at most 200 characters. |

### wm machines wait

`wm machines wait <machine> [--state <state>] [--timeout 10m]`

Wait until a machine is in a state.

| Flag | What it does |
|---|---|
| `--state <state>` | The state to wait for; `running` when left out. |
| `--timeout <duration>` | How long to wait; `10m` when left out. |

### wm machines label

`wm machines label <machine> key=value... [key-]...`

Set a machine's labels: `key=value` sets one, `key-` takes one off. Labels not named stay as they are.

### wm machines rename

`wm machines rename <machine> <name>`

Give a machine another name.

## Commands and files

### wm exec

`wm exec <machine> [flags] -- <command> [args...]`

Run a command in a machine, without a shell. What it wrote is printed as it came, stdout and stderr apart, and `wm` exits with its exit code. A paused machine is woken for it. Flags go before the machine, or between the machine and `--`.

| Flag | What it does |
|---|---|
| `--root` | Run it as root, inside the machine (never on our servers). |
| `--cwd <path>` | Where it starts: an absolute path; the work folder when left out. |
| `--env KEY=VALUE` | A variable for its environment; repeat for more. |

### wm sh

`wm sh <machine> [flags] '<shell line>'`

Run a line of shell in a machine (`sh -lc`), with its pipes and redirections. What it wrote is printed as it came, and `wm` exits with its exit code. It takes the same flags as `wm exec`; with flags after the machine, put the line after `--`.

### wm cp

`wm cp <file> <machine>:work/<path>`   or   `wm cp <machine>:home/<path> <file>`

Copy a file to or from a machine, as a stream. In a machine, a path begins `home/` (its home) or `work/` (where commands start); a path ending in `/` is a folder, and the file keeps its name in it. `-` is standard input or output. At a terminal, the bytes copied and the speed are shown as it goes. One side is always this computer: `wm cp` copies one file, between here and a machine.

## Account

### wm login

`wm login [--scope <scope>...] [--name <name>] [--no-browser]` or `wm login --key`

Sign in through your browser, with GitHub or Google, and keep a key of your own on this computer, for `wm` and `wm-mcp`: the key is made when you approve the code `wm` shows, checked with the API, and kept in a file only you can read. `--scope` asks for less than every scope (repeat it, or join scopes with commas), `--name` names the key, and `--no-browser` shows the address without opening a browser here. `--key` keeps a key you already have instead: asked for at a terminal and not shown as you type, otherwise read from standard input (`wm login --key < keyfile`).

### wm logout

`wm logout`

Forget the key kept on this computer. The key itself still works until it is revoked (`wm keys revoke`).

### wm me

`wm me`

The account and key in use: the key's scopes, projects, rate and end, and whether the account can spend and what is left.

### wm usage

`wm usage [--month YYYY-MM] [--project <project>]`

What each machine ran for and cost in a month.

| Flag | What it does |
|---|---|
| `--month YYYY-MM` | The month; this month when left out. |
| `--project <project>` | Only this project's machines. |

## Projects

### wm projects ls

`wm projects ls`

List the account's projects.

### wm projects create

`wm projects create <name>`

Make a project.

### wm projects rename

`wm projects rename <project> <name>`

Give a project another name.

### wm projects rm

`wm projects rm <project>...`

Delete projects. Only an empty project can be deleted: delete its machines first.

## Keys

### wm keys ls

`wm keys ls`

List the account's machine keys: id, name, the characters it is known by, state, scopes, projects and when it was last used. A key's secret is never shown again after it is made.

### wm keys create

`wm keys create <name> --scope <scope>... [flags]`

Make a key. It can hold only scopes and projects the key in use holds. Its secret is shown this once: store it then. The scopes are `machines:read`, `machines:write`, `machines:exec`, `gpus`, `projects:write`, `keys:write`, or `all`: see [Scopes](https://docs.wheelmachine.ai/keys.html#scopes).

| Flag | What it does |
|---|---|
| `--scope <scope>` | What it may do; repeat, or join with commas. |
| `--project <project>` | A project it is limited to; repeat for more. Every project when left out. |
| `--expires <time>` | When it stops working: in a while (`30d`, `12h`) or on a date (`2026-12-31`). |
| `--rate <n>` | Calls a minute it may make, 1 to 6000; the key in use's own when left out. |

With `-q`, it prints the secret alone, for a script to store.

### wm keys revoke

`wm keys revoke [--yes] <key>...`

Revoke keys: they stop working within seconds, everywhere. This cannot be undone.

| Flag | What it does |
|---|---|
| `-y`, `--yes` | Revoke without being asked. |

## Catalogue

### wm regions

`wm regions`

Places a machine can be asked to run near (`wm machines create --region`). A machine says where it actually runs in its location.

### wm gpus

`wm gpus`

**Coming:** GPUs, where they are and what an hour costs. GPU machines are not open to every account yet, and `wm gpus` says so under the list of what is coming.

## On every command

| Flag | What it does |
|---|---|
| `--json` | Print JSON. |
| `-q`, `--quiet` | Print ids only. |
| `-h`, `--help` | Show the command's flags. |
| `--version` | Print the version (`wm --version`). |
