CLI
Reference for the cubicle command-line tool on macOS and Linux, covering every command, the global --json and --help options, Box arguments (ID or ORG/NAME), CB_CLI_* environment variables, the files it writes, error output, exit codes and API-key mode for CI.
cubicle manages Boxes, access, SSH and the private network from your computer: set it up with
Install the CLI, then sign in with cubicle login.
cubicle <command> [options]Commands
| Command | What it does | Page |
|---|---|---|
login | Sign in by approving a code in the Dashboard. | Account and access |
logout | Disconnect the private network, end the session, remove the login. | Account and access |
whoami | Print your identity and your role in each organization. | Account and access |
version | Print the CLI version and its default API. | Account and access |
keys list, keys add, keys rm | Manage your SSH public keys. | Account and access |
sessions list, sessions revoke | List or end your Dashboard and CLI sign-ins. | Account and access |
members list, members add, members rm | Manage an organization's members. | Account and access |
grants list, grants add, grants rm | Manage who may use a Box. | Account and access |
service-accounts list, service-accounts create, service-accounts rm | Manage an organization's service accounts. | Account and access |
api-keys create, api-keys revoke | Issue or revoke a service account's API keys. | Account and access |
boxes list, boxes bases | List Boxes, or the base images an organization can use. | Box commands |
boxes create, boxes get | Create a Box, or print one as JSON. | Box commands |
boxes start, boxes stop, boxes delete | Change a Box's desired state, and optionally wait for it. | Box commands |
exec | Run one command in a Box and print its output. | Box commands |
snapshot, snapshots, restore | Take, list and restore disk snapshots. | Box commands |
tunnel install, tunnel uninstall, tunnel status | Add, remove or check the optional root network helper. | Networking and SSH |
connect, disconnect, status | Join or leave the private network, or print its state. | Networking and SSH |
devices list, devices revoke | List or revoke this account's private network devices. | Networking and SSH |
ssh-config, ssh | Write an OpenSSH alias for a Box, or connect and open SSH. | Networking and SSH |
box is an alias for boxes: cubicle box list works too.
Global options
| Flag | Value | Default | Meaning |
|---|---|---|---|
--json | none | Off | Print the API response as JSON instead of the human format. |
-h, --help | none | Off | Print the usage summary of all commands. |
--api URL belongs to cubicle login only; see cubicle login.
- Put options anywhere before
--. After--, everything goes to the command in the Box (exec) or tossh(ssh). Other commands ignore it. - A command ignores options it does not use, such as
--waitonboxes list. - An option the CLI does not know is an error. The message contains
Unknown option '--<name>', and the command exits 1. cubiclewith no command, andcubicle --help, print the usage and exit 2.cubicle <command> --helpprints the same usage and exits 0.
JSON output
With --json, a command prints its result on stdout as JSON with 2-space indentation. For most
commands that is the API's response.
boxes get,connect,disconnect,statusanddevices listalways print JSON.keys rm,sessions revoke,members rm,grants add,grants rm,service-accounts rm,api-keys revokeanddevices revokeprint nothing when they succeed, with or without--json.login,logout,tunnel install,tunnel uninstallandsshignore--json.- Errors are always plain text on stderr, also with
--json. Check the exit code.
Box arguments
Commands that take BOX accept one of these:
| Form | Example | Notes |
|---|---|---|
| Box ID | 0b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10 | A UUID. Used as is, without a lookup. |
ORG/NAME | acme/job-1 | ORG is the organization's name or ID. NAME is exact. |
The CLI does not accept a bare name such as job-1, although the HTTP API does.
- A bare name fails with
BOX must be a box ID or ORG/NAME. - A missing argument fails with
missing BOX argument. - For
ORG/NAME, the CLI looks the name up in the organization's list of Boxes. If none matches, it fails withno box acme/job-1. - That list includes a deleted Box until its Node has removed it. Right after you delete
acme/job-1and create a new one with the same name,acme/job-1can still refer to the deleted Box, and commands fail withnot_found: box not found. Use the new Box's ID until the old one has leftcubicle boxes list.
Errors
Errors go to stderr, and the command exits 1, or 2 for an unknown command.
| Error | Format | Example |
|---|---|---|
| The API refused the request | <code>: <message> | conflict: a box named job-1 already exists |
| The API refused your login or key (401) | <message> | login expired; run `cubicle login` |
| The API did not answer | cannot reach <API URL>: <reason> | cannot reach https://api.cubicle.sh: … |
| The CLI rejected the arguments | A usage: line or a short sentence | usage: cubicle boxes create --org ORG NAME |
| Anything unexpected | cubicle: and a stack trace |
Each API request times out after 30 s. The CLI does not retry a request that fails, also not a
429 rate_limited one: the command exits 1. Troubleshooting has fixes for
common errors and points to the guide that fixes each feature's own errors, and
Errors lists the API's error codes.
Exit codes
| Code | When |
|---|---|
0 | The command succeeded. |
1 | Any error, including a failed --wait, and an exec, snapshot or restore operation that ended failed or unknown. |
2 | No command, cubicle --help, or an unknown command. |
| The command's exit code | exec, when the command ran. A command that timed out exits 124. |
ssh's exit code | ssh. 255 when ssh reports none. |
255 | The launcher found no Node.js and printed cubicle: Node.js 24 not found; set CB_CLI_NODE_BINARY. |
Environment variables
| Variable | Default | Meaning |
|---|---|---|
CB_CLI_API_URL | Unset | The API that cubicle login signs in to when --api is not given. With CB_CLI_API_KEY, the API every command uses. Otherwise commands use the API URL stored with your login. |
CB_CLI_API_KEY | Unset | A service account API key (cbk_…) that every command uses instead of the stored login. Requires CB_CLI_API_URL. See API-key mode. |
CB_CLI_CONFIG_DIR | ~/.config/cubicle | The directory for the login details, the file credential store and the private network's background process. |
CB_CLI_CREDENTIAL_STORE | Chosen automatically | Where cubicle login stores the token: keychain, secret-tool or file. Automatic means the Keychain on macOS, secret-tool on Linux with a D-Bus session and secret-tool installed, and the file otherwise. |
CB_CLI_SSH_DIR | ~/.ssh | Where ssh-config and ssh write cubicle_config and cubicle_known_hosts, and the config file there that gets the Include line. The default identity file stays ~/.ssh/id_ed25519. |
CB_CLI_NODE_BINARY | Found automatically | The Node.js executable the launcher runs. Without it, the launcher tries the bundled Node.js, then node on your PATH, /opt/homebrew/bin/node, /usr/local/bin/node and /usr/bin/node. |
CB_CLI_CREDENTIAL_STORE takes effect when you log in. The login records which store holds its
token, and later commands read it from there. Any other value means automatic.
Files the CLI writes
| Path | Written by | Contents |
|---|---|---|
~/.config/cubicle/login.json | login | The API URL, your identity, the session's expiry and the token's store. Readable only by you. |
~/.config/cubicle/credentials.json | login, with the file store | The session token. Readable only by you. |
macOS Keychain, service cubicle | login, with the Keychain store | The session token, under an account named after the API URL. |
Secret Service item Cubicle | login, with secret-tool | The session token in your desktop keyring, with attributes service=cubicle and api=<API URL>. |
~/.config/cubicle/vpn.sock | connect, ssh | The private network background process's control socket. |
~/.config/cubicle/vpn.log | connect, ssh | The background process's log. |
~/.config/cubicle/vpn-error.txt | connect, ssh | The background process's last error. disconnect removes it. |
~/.ssh/cubicle_config | ssh-config, ssh | One Host block per alias. |
~/.ssh/cubicle_known_hosts | ssh-config, ssh | One pinned host key per Box. |
~/.ssh/config | ssh-config, ssh | An Include line for cubicle_config, added once at the top. |
/opt/cubicle/tunnel, /etc/cubicle/cli-helper.json | tunnel install, as root | The helper's root-owned copy of the CLI, and the OS user allowed to control it. |
/var/lib/cubicle/cli/ | The root helper | This computer's device keys, one per login, and the tunnel's state. Kept when you uninstall. |
/etc/resolver/cubicle.internal | The root helper, on macOS | DNS for *.cubicle.internal while connected. |
logout removes login.json, credentials.json and the token from the Keychain or Secret
Service. Install the CLI lists what the installer writes.
API-key mode
Set CB_CLI_API_KEY to a service account API key and CB_CLI_API_URL to the API. Every command
then authenticates with the key and never uses your stored login. Use this in CI and other
unattended jobs.
export CB_CLI_API_URL=https://api.cubicle.sh
export CB_CLI_API_KEY=cbk_…
cubicle whoami # acme/ci (acme:member)
cubicle boxes create --org acme job-1 --wait
cubicle exec acme/job-1 -- sh -c 'echo hello'
cubicle boxes delete acme/job-1Without CB_CLI_API_URL, every command that would use your login fails with
CB_CLI_API_KEY requires CB_CLI_API_URL.
- These commands work with a key:
whoami,boxes list,boxes bases,boxes create,boxes get,boxes start,boxes stop,boxes delete,exec,snapshot,snapshotsandrestore. - These fail with
api_key_not_allowed: API keys cannot use this route:keys,sessions,members,grants,service-accounts,api-keys,connect,devices,ssh-configandssh. Without the tunnel installed,connectandsshfail first with "the Cubicle tunnel is not installed". - With a
readkey, onlywhoami,boxes list,boxes bases,boxes getandsnapshotswork. The commands that change something fail withinsufficient_scope: this API key is read-only. - A key sees only its own organization. Other organizations' Boxes fail with
not_found.boxes listwithout--orglists the key's organization. execneeds a grant on the Box. A service account gets one on every Box it creates.version,tunnel status,statusanddisconnectdo not call the API.logoutstill removes a stored login if there is one.
Create a service account and a key shows how to get a key.

