Box commands
Reference for the cubicle Box commands boxes list, bases, create, get, start, stop and delete, exec, snapshot, snapshots and restore, with options, --wait behavior and the 10-minute deadline, output formats, exit codes, errors and what the CLI cannot do yet.
These commands create and manage Boxes, run commands in them and take snapshots. BOX is a Box ID
or ORG/NAME, such as acme/job-1; see Box arguments. They work with your
login and with an API key (API-key mode). Box lifecycle
explains the states and generations that their output shows.
boxes start,boxes stop,boxes delete,snapshotandrestoreneed a grant on the Box, or theowneroradminrole in its organization.boxes create --snapshotneeds the same on the snapshot's Box.execneeds a grant even for owners and admins. See Roles.- While a snapshot or restore of the Box runs,
boxes start,boxes stopandboxes deletefail withconflict: a snapshot or restore is in progress for this box.
Waiting
| Command | Waits | Until | Time limit |
|---|---|---|---|
boxes create --wait | On request | ssh.ready is true: the Box runs and accepts SSH and exec | 10 min |
boxes create --no-start --wait | On request | The Box's state is stopped | 10 min |
boxes start --wait | On request | ssh.ready is true | 10 min |
boxes stop --wait | On request | The state is stopped at the generation of this stop | 10 min |
boxes delete --wait | On request | The Box no longer resolves, which happens right away | 10 min |
exec, snapshot, restore | Always | The operation ends done, failed or unknown | None |
--waitreads the Box every 1 s. If the Box turnsfailed, the command stops withbox failed: <error>. After 10 minutes it stops withtimed out waiting for the box. Both exit 1, and the request stays in effect.--waitstops at the firstfailedreport it reads, even one left over from an earlier failed start. After a failure, start the Box without--waitand checkcubicle boxes listinstead; seebox failed.exec,snapshotandrestoreread the operation every 500 ms, with no time limit in the CLI. Interrupting the CLI, for example with Ctrl-C, stops the wait, not the operation.ssh.readydescribes the Box. It does not check your own grant or SSH key.
cubicle boxes list
Lists Boxes, in all your organizations or in one.
cubicle boxes list [--org ORG] [--json]| Flag | Value | Default | Meaning |
|---|---|---|---|
--org | Organization name or ID | All your organizations | List only this organization's Boxes. |
- Without
--org, it lists the Boxes of every organization where you are an active member, by organization name and then creation time. With an API key, it lists the key's organization. - With
--org, it lists that organization's Boxes by creation time. - A deleted Box stays listed, with
desired=deleted, until its Node has removed it. --jsonprints an array of Box objects. Without--org, each also hasviewer(your role and whether you hold a grant),grantsandopenVpnSessions, the number of open private network sessions that route the Box.
Output is one line per Box, or no boxes:
<box ID> <org>/<name> <state> desired=<desired state>@<generation> node=<node> ssh=<ready or reason>| Field | Meaning |
|---|---|
state | The Box's current state, such as running, stopped, hibernated or unknown. |
desired | The state last requested, and the generation of that request. |
node | The Node that runs the Box. (unhealthy) follows the name when the Node has stopped reporting. |
ssh | ready, or why SSH and exec cannot be used yet, such as not_requested or generation_pending. |
What each state means lists every state, and
When a Box is ready every readiness reason. Calls
GET /v1/boxes or, with --org,
GET /v1/orgs/{org}/boxes.
cubicle boxes list --org acme0b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10 acme/job-1 running desired=running@3 node=worker-1 ssh=ready
a5c1e9d3-7b2f-4a6e-8d0c-3f9b1e7a5c2d acme/job-2 stopped desired=stopped@2 node=worker-1 ssh=not_requestedcubicle boxes bases
Lists the base images an organization can create Boxes from.
cubicle boxes bases --org ORG [--json]| Flag | Value | Default | Meaning |
|---|---|---|---|
--org | Organization name or ID | Required | The organization. |
- Output: one line per base,
<base ID> <name> available|unavailable. availablemeans at least one healthy Node that takes new Boxes has the image. It does not check free capacity.--jsonalso prints each base's default size asspec.
Calls GET /v1/orgs/{org}/bases.
cubicle boxes bases --org acmedefault Default available
omarchy Omarchy availablecubicle boxes create
Creates a Box from a base image or from a snapshot.
cubicle boxes create --org ORG NAME [--vcpus N] [--memory MiB] [--disk GiB]
[--base default|omarchy | --snapshot SNAPSHOT_ID]
[--no-start] [--wait] [--json]| Flag | Value | Default | Meaning |
|---|---|---|---|
--org | Organization name or ID | Required | The organization that owns the Box. |
--vcpus | 1 to 64 | The base's size, or the source Box's with --snapshot | Virtual CPUs. |
--memory | 256 to 262144 MiB | The base's size, or the source Box's with --snapshot | Memory in MiB. |
--disk | 1 to 2048 GiB | The base's size, or the source Box's with --snapshot | Disk in GiB. With --snapshot, at least the source Box's disk. |
--base | default or omarchy | default | The base image. Not allowed with --snapshot. |
--snapshot | Snapshot ID | None | Start from this snapshot's disk instead of a base image. |
--no-start | none | Off | Create the Box stopped. |
--wait | none | Off | Wait until the Box is ready, or stopped with --no-start. |
The default base is 2 vCPUs, 2048 MiB and 12 GiB. The omarchy base is 4 vCPUs, 8192 MiB and
40 GiB. Limits and defaults lists every limit.
NAMEis required in the CLI. It matches^[a-z0-9][a-z0-9-]{0,62}$and must be unique among the organization's Boxes.- Any active member can create a Box when the organization allows it. You get a grant on the new Box.
- With
--snapshot, the snapshot must belong toORGand becomplete. The new Box runs on the snapshot's Node and keeps the snapshot's base image.cubicle snapshots SOURCE_BOXprints snapshot IDs. - Each run sends its own
Idempotency-Key, so running the command again makes a new request. With the same name, it fails because the name is taken. - Output: the Box's line, as in
boxes list, when the request is accepted or, with--wait, when the wait ends.--jsonprints the Box object.
| Error | Cause |
|---|---|
choose --base or --snapshot, not both | Both options were given. |
usage: cubicle boxes create --org ORG NAME | --org or NAME is missing. |
box_create_disabled: this organization cannot create boxes; ask an operator to enable it | The organization may not create Boxes yet, as with a new personal organization. |
conflict: a box named job-1 already exists | The name is in use. |
capacity: no healthy node with the default base image has capacity for this box | No Node has room. Try again later or ask for a smaller Box. |
invalid_request: disk must be at least 12 GiB (the snapshot's size) | --disk is smaller than the source Box's disk. |
conflict: snapshot is not complete | The snapshot is still pending, or failed. |
Calls POST /v1/orgs/{org}/boxes.
cubicle boxes create --org acme job-1 --wait0b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10 acme/job-1 running desired=running@1 node=worker-1 ssh=readycubicle boxes get
Prints one Box as JSON.
cubicle boxes get BOXNo options. The command always prints JSON, with or without --json. The object has the Box's
state, desired and observed states, spec, node, ssh and console readiness,
privateIp, hibernateAt, restartRequired, deletion and more. A deleted Box fails with
not_found: box not found.
Calls GET /v1/boxes/{box}, which documents every field.
cubicle boxes get acme/job-1 | jq '{state, desired, ssh, hibernateAt}'{
"state": "running",
"desired": { "state": "running", "generation": 3 },
"ssh": { "ready": true, "reason": null },
"hibernateAt": "2026-11-05T10:42:17.311Z"
}cubicle boxes start
Starts a stopped Box or resumes a hibernated one.
cubicle boxes start BOX [--wait] [--json]| Flag | Value | Default | Meaning |
|---|---|---|---|
--wait | none | Off | Wait until ssh.ready is true. |
- A hibernated Box resumes from its saved memory. A stopped Box boots from its disk.
- It also clears the hold a Box gets when its host restarts (
restartRequired). - On a running Box it does not reboot anything, but it advances the generation; see Generations.
- Output: the Box's line.
--jsonprints the Box object.
Calls POST /v1/boxes/{box}/start.
cubicle boxes start acme/job-1 --wait0b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10 acme/job-1 running desired=running@3 node=worker-1 ssh=readycubicle boxes stop
Stops a Box. Its disk is kept; its memory is not.
cubicle boxes stop BOX [--wait] [--json]| Flag | Value | Default | Meaning |
|---|---|---|---|
--wait | none | Off | Wait until the Box is stopped at this stop's generation. |
- On a hibernated Box, stop discards the saved memory. The next start boots from the disk.
- The CLI cannot hibernate a Box. See Not in the CLI.
- Output: the Box's line.
--jsonprints the Box object.
Calls POST /v1/boxes/{box}/stop.
cubicle boxes stop acme/job-1 --wait0b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10 acme/job-1 stopped desired=stopped@4 node=worker-1 ssh=not_requestedcubicle boxes delete
Deletes a Box permanently, with its disk and every snapshot of it.
cubicle boxes delete BOX [--wait] [--json]| Flag | Value | Default | Meaning |
|---|---|---|---|
--wait | none | Off | Wait until the Box no longer resolves. This does not wait for cleanup. |
- It also fails while another Box is still being created from one of its snapshots:
conflict: box job-2 is still being created from a snapshot of this box. - The name is free for a new Box at once.
- Output:
<box ID> deletion pending. With--wait:<box ID> deletion deleted. --jsonprints the Box object with"deletion": "pending". With--wait, it prints{ "id": "<box ID>", "state": "deleted" }.--waitreturns at once, because a deleted Box stops resolving right away. Its Node releases the capacity when it has removed the Box: to wait for that, checkcubicle boxes list --org ORGuntil the Box is gone.
Calls DELETE /v1/boxes/{box}. See
Deleting a Box.
cubicle boxes delete acme/job-10b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10 deletion pendingcubicle exec
Runs one command in a running Box, waits for it and prints its output.
cubicle exec BOX [--timeout MS] [--json] -- COMMAND [ARGS...]| Flag | Value | Default | Meaning |
|---|---|---|---|
--timeout | 100 or more, in ms | 60000 | Kill the command after this many ms. Values above 600000 (10 min) become 600000. |
- Everything after
--is the command, run as an argv without a shell. Usesh -c '…'for pipes, redirects,&&and variables. Put CLI options before--. Without--and a command, the CLI printsusage: cubicle exec BOX -- COMMAND [ARGS...]. - The command runs as your guest account, in its home directory. It has no stdin and no TTY.
- Without a grant on the Box it fails with
forbidden: an explicit box grant is required. - The Box must be running: otherwise
conflict: box is not running. Runcubicle boxes start BOX --waitfirst. - The CLI prints the command's stdout on stdout and its stderr on stderr, once the command ends. Output is not streamed.
- stdout and stderr together are cut at 64 KiB. The CLI then also prints
cubicle: output truncatedon stderr. - The CLI exits with the command's exit code. A command killed by
--timeoutexits124, and the CLI prints the output the command wrote before it was killed.--jsonshows"timedOut": true. - An operation that ends
failedorunknownexits 1. Without--json, the CLI printsexec failed: <error>orexec unknown: <error>. Anunknowncommand may or may not have run; see Operations record every request. --jsonprints the operation, with the output inresult. The exit code is still the command's.- The CLI sends no
Idempotency-Keywithexecand does not retry it, so running the samecubicle execagain runs the command again.
Calls POST /v1/boxes/{box}/exec, then
GET /v1/operations/{operation}.
Run commands covers shell syntax, long jobs and timeouts.
cubicle exec acme/job-1 -- sh -c 'echo hello; echo oops >&2; exit 3'
echo "exit code: $?"hello
oops
exit code: 3With --json:
cubicle exec acme/job-1 --json -- echo hello{
"id": "c4e8a2f6-1b3d-4f5a-9c7e-2d4f6a8b0c1e",
"boxId": "0b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10",
"type": "exec",
"state": "done",
"attempt": 1,
"progress": null,
"result": {
"exitCode": 0,
"stdout": "hello\n",
"stderr": "",
"timedOut": false,
"truncated": false
},
"error": null,
"createdAt": "2026-11-05T09:20:01.114Z",
"startedAt": "2026-11-05T09:20:01.402Z",
"completedAt": "2026-11-05T09:20:01.587Z"
}cubicle snapshot
Takes a disk snapshot of a stopped Box and waits until it ends.
cubicle snapshot BOX NAME [--json]No options besides --json.
- The Box must be stopped: otherwise
conflict: stop the box before taking a snapshot. Runcubicle boxes stop BOX --waitfirst. Stopping a hibernated Box discards its saved memory. NAMEmatches^[a-z0-9][a-z0-9._-]{0,62}$. Names need not be unique.- Snapshots explains what a snapshot holds and where it is kept.
- Output:
snapshot <NAME>: done, orsnapshot <NAME>: failed (<error>). The command exits 0 only when the snapshot is done. --jsonprints the operation.cubicle snapshots BOXprints the new snapshot's ID.
Calls POST /v1/boxes/{box}/snapshots.
cubicle boxes stop acme/job-1 --wait
cubicle snapshot acme/job-1 before-upgrade0b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10 acme/job-1 stopped desired=stopped@4 node=worker-1 ssh=not_requested
snapshot before-upgrade: donecubicle snapshots
Lists a Box's snapshots, newest first.
cubicle snapshots BOX [--json]No options besides --json. Any active member of the Box's organization can list them.
- Output: one line per snapshot,
<snapshot ID> <name> <status> <created at>. <status>ispending,completeorfailed.--jsonprints an array withid,name,status,operationId,createdAtandcompletedAt.
Calls GET /v1/boxes/{box}/snapshots.
cubicle snapshots acme/job-13f2a9c1e-7b4d-4e8f-a6c2-1d9e0b8f7a3c before-upgrade complete 2026-11-05T10:04:12.000Zcubicle restore
Replaces a stopped Box's disk with one of its own snapshots, and waits until that ends.
cubicle restore BOX SNAPSHOT_ID [--json]No options besides --json.
- The Box must be stopped: otherwise
conflict: stop the box before restoring a snapshot. SNAPSHOT_IDis an ID fromcubicle snapshots BOX, not a name. A snapshot of another Box fails withnot_found: snapshot not found; one that is not complete fails withconflict: snapshot is not complete.- Every file on the Box's disk is replaced. The Box stays stopped; start it with
cubicle boxes start BOX --wait. - Output:
restore: done, orrestore: failed (<error>). The command exits 0 only when the restore is done.--jsonprints the operation.
To copy a snapshot into a new Box instead, use cubicle boxes create --snapshot SNAPSHOT_ID.
Calls POST /v1/boxes/{box}/restore.
cubicle restore acme/job-1 3f2a9c1e-7b4d-4e8f-a6c2-1d9e0b8f7a3c
cubicle boxes start acme/job-1 --waitrestore: done
0b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10 acme/job-1 running desired=running@5 node=worker-1 ssh=readyNot in the CLI
These tasks need the TypeScript SDK or the HTTP API.
| Task | TypeScript SDK | HTTP API |
|---|---|---|
| Hibernate a Box | box.hibernate() | POST /v1/boxes/{box}/hibernate |
| List a Box's operations | box.listOperations() | GET /v1/boxes/{box}/operations |
| Read one operation | cubicle.operations.get(id) | GET /v1/operations/{operation} |
| Run a command in another directory | box.exec(argv, { cwd }) | POST /v1/boxes/{box}/exec with cwd |
| Keep more than 64 KiB of output, up to 1 MiB | box.exec(argv, { maxOutputBytes }) | POST /v1/boxes/{box}/exec with maxOutputBytes |
| List an organization's snapshots that you can create Boxes from | cubicle.listSnapshots() | GET /v1/orgs/{org}/snapshots |
| Refer to a Box by its bare name | cubicle.boxes.get("job-1") | GET /v1/boxes/job-1, with ?org= when the name is in several organizations |
- The desktop console is in the Dashboard only. See Use the desktop console.
- Streaming exec output, stdin or a TTY, file transfer, port forwarding, public URLs, fork, resize,
rename and reboot are in no surface yet; see Not available yet. To
copy files, use
scporrsyncover SSH; see Copy files over SSH.
Boxes and handles shows how to get a box handle in the SDK.
Account and access commands
Reference for the cubicle commands login, logout, whoami, version, keys (SSH public keys), sessions, members, grants, service-accounts and api-keys, with usage, options, output formats, required roles, errors and examples.
Networking and SSH commands
Reference for the cubicle commands tunnel install, uninstall and status, connect, disconnect, status, devices list and revoke, ssh-config and ssh, covering the root network helper, the private WireGuard network, JSON status fields, SSH aliases, host keys and exit codes.

