Appearance
ssh cli commands
The management CLI runs over SSH — nothing to install, and your SSH key is your identity. The reserved username cli spawns no box; every command is scoped to the boxes owned by your key's fingerprint.
sh
ssh cli@host <command>Every <box> below is a box reference: a bare name (your default workspace), ws1/box1, a full id, or any id prefix that matches one box. A reference matching more than one is refused with both named.
Commands
| Command | Description |
|---|---|
ls (ps, list) | List your boxes: WORKSPACE BOX NAME IMAGE STATE AGE, grouped by workspace. STATE is one of starting / running / suspended / pinned / kept / ephemeral (see box status). |
ws create <name> | Create a workspace (a group of boxes with their own /wrk, homes, and secrets). |
ws ls | List your workspaces: WORKSPACE · BOXES · PROFILE (the box profile its boxes default to, - for none). |
ws profile <ws> <profile>|- | Point a workspace at one of your box profiles: boxes spawned there start from it when their spec names no image. A default, never an override — precedence is explicit spec > workspace default > nothing. - clears it. Refuses a profile that is not yours, rather than storing a name that would fail at every spawn. |
ws rm <name> (--force) | Remove a workspace; refused if it has boxes unless --force. |
profile set <name> | Store a box profile — a named box configuration — reading its JSON definition from stdin: ssh cli@host profile set go-dev < go-dev.json. Validated on the way in: an unknown flavor, lifetime, duration or JSON key is refused rather than stored. Replaces any existing profile of that name. Creating a NEW one is bounded by your tier (--quota-*; editing an existing one always works). |
profile ls | Your profiles: PROFILE · BASE · BUILD · UPDATED. BUILD is the build a spawn resolves to (- = never built successfully), flagged (base changed) when the base catalog image has been rebuilt since — reported only; nothing rebuilds on its own. |
profile show <name> | Print the definition, canonicalised — profile show x > f, edit, profile set x < f round-trips. |
profile build <name> | Compile the profile into an image: spawn a throwaway box from build.base, run build.script in it as root (under set -e), stop the box, flatten its disk into a numbered image, destroy the box. Foreground and slow — minutes — and streams the script's output as it runs. The build box counts against your box quota, receives no secrets, and has unrestricted egress; the build is bounded at 30 minutes. microVM backend only: a host that cannot capture a disk says so. |
profile builds <name> | The profile's build history, newest first: BUILD · STATUS · BASE · STARTED · TOOK. Marks which build is (current) — the newest succeeded one, which is what the name resolves to — and prints the newest failure's reason and log tail. A build shown reclaimed succeeded but had its image freed: only the newest 3 keep theirs, and a build a box is still running from is never freed. |
profile rm <name> | Delete a profile. Its built images are reclaimed by the daemon once no box is still booting from them, so removing a profile never disturbs boxes already spawned from it. Reports a miss, so profile rm typo does not look like it worked. |
up <[ws/]name[:image[:flavor]][^ttl]> (spawn) | Start a box without attaching a shell. ^ttl (30m, 2h) gives it a hard deadline — it is destroyed then, whatever it is doing. |
rm <box> (delete, destroy) | Remove one of your boxes (owner-checked). |
suspend <box> | Snapshot a running box to disk now (microVM only; other backends report it's unsupported). |
resume <box> | Wake a suspended box without connecting. |
rename <box> <new> (mv) | Rename a box; its persistent home follows. Refused if the new name is already yours. |
durable <box> on|off | Mark a box durable — it persists (never idle-reaped) but still auto-suspends when idle. Turning it on needs a verified account; off is always allowed. |
share <box> [--ttl 24h] [--label "n"] | Mint a share link for a box: prints ssh hbxs_<token>@<host> (shown once) that gives any holder a shell in that box. --ttl sets expiry (default 24h; 0 = never). Needs a verified account. |
shares [<box>] | List your active share links (ID · BOX · LABEL · EXPIRES · LAST USED); never the token. Optional box ref filters to one box. |
unshare <id> | Revoke a share link by id; its hbxs_<token> stops working immediately. |
ready <box> (wait) | Block until the box is running with its agent connected (30s timeout, non-zero exit on timeout) — for scripts. |
clone <src> <dst> (fork) | Fork a box's persistent home into a new box on the same image (needs --homes-dir). |
snapshot <box> [name] | Capture a box's disk state (microVM). Name defaults to a timestamp. |
snapshot ls <box> | List a box's snapshots: SNAPSHOT SIZE AGE. |
snapshot fork <src> <name> <new[^ttl]> | Create a new box that boots from <src>'s snapshot (CoW, cheap). <new> takes the username grammar, so ^ttl gives the fork a hard deadline — snapshot fork base nightly job^20m forks a box that is destroyed 20 minutes later. Omit it and the fork behaves like any named box: it auto-suspends when idle and has no deadline. Your tier clamps the deadline exactly as it does on a spawn. |
snapshot restore <box> <name> | Roll a box back to a snapshot (it reboots into that state). Persistent-tier boxes. |
snapshot rm <box> <name> | Delete a snapshot. |
apikeys create <name> [-w <ws>] [--ttl <dur>] | Mint an HTTP API key (hbx_…), printed once. -w/--workspace confines it to one workspace — its boxes, its /wrk drive, its secrets, and nothing else. --ttl gives it a deadline (24h, 30m); it must be positive. Neither flag = the whole account, forever. See scoped keys. |
apikeys ls | List your API keys: NAME · SCOPE · CREATED · EXPIRES · LAST USED (never the secret). SCOPE is account or workspace:<ws>. |
apikeys rm <name> (revoke) | Revoke an API key. |
acc · acc register <handle> | Show / create your account (verification, quotas). |
mcp | Serve your per-key MCP plane over this SSH connection — point an MCP client at ssh cli@host mcp. |
secret set [-w <ws>] [-b <box>] <NAME> | Store a secret (value read from stdin). Scope: none = account (all boxes), -w <ws> = a workspace, -w <ws> -b <box> (or --box <ws>/<box>) = one box. Appears as $NAME; NAME is env-var-shaped, non-HOPBOX_. A box sees them layered, box > workspace > account. |
secret ls [-w <ws>] [-b <box>] | List secret names + scope (never the values); filters to a tier. |
secret rm [-w <ws>] [-b <box>] <NAME> | Delete a secret at a scope. |
asks | List questions your agents are blocked on: ID BOX KIND QUESTION OPTIONS. |
answer <id> <choice> | Answer a pending ask — unblocks the agent with your choice (free text allowed). |
help | Usage banner. Bare ssh cli@host prints the banner and your fleet. |
sh
ssh cli@box.hopbox.dev ls
ssh cli@box.hopbox.dev up box1:python:big # start, don't attach
ssh cli@box.hopbox.dev ready box1 # block until it's up (scripts)
ssh cli@box.hopbox.dev rename box1 box2 # its home follows
ssh cli@box.hopbox.dev suspend box1 # snapshot to disk now (microVM)
ssh cli@box.hopbox.dev rm box1
ssh cli@box.hopbox.dev # banner + your boxesSnapshots copy the box's copy-on-write disk with the device briefly frozen for a consistent image (they live beside the box and are lost when it's destroyed — restore + fork-from-snapshot are coming).
Notes
- Key = identity. A different SSH key is a different owner and sees none of your boxes. There is no signup and no separate login.
- Spawn by connecting. There's no
createcommand — you make a box just by connecting to a name:ssh <name>@host. See SSH & the front door. - For AIs, the same fleet is driven programmatically over the MCP plane (
fleet_get,box_delegate,fleet_apply).
See also
- SSH & the front door — spawning boxes and the username grammar.
- The AI-control plane — the MCP twin of these commands.