Cubicle

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

CommandWhat it doesPage
loginSign in by approving a code in the Dashboard.Account and access
logoutDisconnect the private network, end the session, remove the login.Account and access
whoamiPrint your identity and your role in each organization.Account and access
versionPrint the CLI version and its default API.Account and access
keys list, keys add, keys rmManage your SSH public keys.Account and access
sessions list, sessions revokeList or end your Dashboard and CLI sign-ins.Account and access
members list, members add, members rmManage an organization's members.Account and access
grants list, grants add, grants rmManage who may use a Box.Account and access
service-accounts list, service-accounts create, service-accounts rmManage an organization's service accounts.Account and access
api-keys create, api-keys revokeIssue or revoke a service account's API keys.Account and access
boxes list, boxes basesList Boxes, or the base images an organization can use.Box commands
boxes create, boxes getCreate a Box, or print one as JSON.Box commands
boxes start, boxes stop, boxes deleteChange a Box's desired state, and optionally wait for it.Box commands
execRun one command in a Box and print its output.Box commands
snapshot, snapshots, restoreTake, list and restore disk snapshots.Box commands
tunnel install, tunnel uninstall, tunnel statusAdd, remove or check the optional root network helper.Networking and SSH
connect, disconnect, statusJoin or leave the private network, or print its state.Networking and SSH
devices list, devices revokeList or revoke this account's private network devices.Networking and SSH
ssh-config, sshWrite 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

FlagValueDefaultMeaning
--jsonnoneOffPrint the API response as JSON instead of the human format.
-h, --helpnoneOffPrint 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 to ssh (ssh). Other commands ignore it.
  • A command ignores options it does not use, such as --wait on boxes list.
  • An option the CLI does not know is an error. The message contains Unknown option '--<name>', and the command exits 1.
  • cubicle with no command, and cubicle --help, print the usage and exit 2. cubicle <command> --help prints 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, status and devices list always print JSON.
  • keys rm, sessions revoke, members rm, grants add, grants rm, service-accounts rm, api-keys revoke and devices revoke print nothing when they succeed, with or without --json.
  • login, logout, tunnel install, tunnel uninstall and ssh ignore --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:

FormExampleNotes
Box ID0b3f6c2e-8d4a-4f6e-9c1d-7a2b5e8f9d10A UUID. Used as is, without a lookup.
ORG/NAMEacme/job-1ORG 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 with no box acme/job-1.
  • That list includes a deleted Box until its Node has removed it. Right after you delete acme/job-1 and create a new one with the same name, acme/job-1 can still refer to the deleted Box, and commands fail with not_found: box not found. Use the new Box's ID until the old one has left cubicle boxes list.

Errors

Errors go to stderr, and the command exits 1, or 2 for an unknown command.

ErrorFormatExample
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 answercannot reach <API URL>: <reason>cannot reach https://api.cubicle.sh: …
The CLI rejected the argumentsA usage: line or a short sentenceusage: cubicle boxes create --org ORG NAME
Anything unexpectedcubicle: 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

CodeWhen
0The command succeeded.
1Any error, including a failed --wait, and an exec, snapshot or restore operation that ended failed or unknown.
2No command, cubicle --help, or an unknown command.
The command's exit codeexec, when the command ran. A command that timed out exits 124.
ssh's exit codessh. 255 when ssh reports none.
255The launcher found no Node.js and printed cubicle: Node.js 24 not found; set CB_CLI_NODE_BINARY.

Environment variables

VariableDefaultMeaning
CB_CLI_API_URLUnsetThe 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_KEYUnsetA 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/cubicleThe directory for the login details, the file credential store and the private network's background process.
CB_CLI_CREDENTIAL_STOREChosen automaticallyWhere 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~/.sshWhere 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_BINARYFound automaticallyThe 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

PathWritten byContents
~/.config/cubicle/login.jsonloginThe API URL, your identity, the session's expiry and the token's store. Readable only by you.
~/.config/cubicle/credentials.jsonlogin, with the file storeThe session token. Readable only by you.
macOS Keychain, service cubiclelogin, with the Keychain storeThe session token, under an account named after the API URL.
Secret Service item Cubiclelogin, with secret-toolThe session token in your desktop keyring, with attributes service=cubicle and api=<API URL>.
~/.config/cubicle/vpn.sockconnect, sshThe private network background process's control socket.
~/.config/cubicle/vpn.logconnect, sshThe background process's log.
~/.config/cubicle/vpn-error.txtconnect, sshThe background process's last error. disconnect removes it.
~/.ssh/cubicle_configssh-config, sshOne Host block per alias.
~/.ssh/cubicle_known_hostsssh-config, sshOne pinned host key per Box.
~/.ssh/configssh-config, sshAn Include line for cubicle_config, added once at the top.
/opt/cubicle/tunnel, /etc/cubicle/cli-helper.jsontunnel install, as rootThe helper's root-owned copy of the CLI, and the OS user allowed to control it.
/var/lib/cubicle/cli/The root helperThis computer's device keys, one per login, and the tunnel's state. Kept when you uninstall.
/etc/resolver/cubicle.internalThe root helper, on macOSDNS 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-1

Without 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, snapshots and restore.
  • These fail with api_key_not_allowed: API keys cannot use this route: keys, sessions, members, grants, service-accounts, api-keys, connect, devices, ssh-config and ssh. Without the tunnel installed, connect and ssh fail first with "the Cubicle tunnel is not installed".
  • With a read key, only whoami, boxes list, boxes bases, boxes get and snapshots work. The commands that change something fail with insufficient_scope: this API key is read-only.
  • A key sees only its own organization. Other organizations' Boxes fail with not_found. boxes list without --org lists the key's organization.
  • exec needs a grant on the Box. A service account gets one on every Box it creates.
  • version, tunnel status, status and disconnect do not call the API. logout still removes a stored login if there is one.

Create a service account and a key shows how to get a key.

On this page