Cubicle

Quickstart

Install the cubicle CLI, log in, create a service account with a write API key, then use @cubicle/sdk from TypeScript to create a Box, run uname -a in it, print the output and delete the Box.

You will create a Box, run uname -a in it from TypeScript, read its output and delete it. Concepts defines the terms this guide uses.

Prerequisites

  • A Cubicle account. Cubicle is invite-only: sign in with the email address on your invitation.
  • Membership in an organization where you may create Boxes. This guide calls it acme.
    • To create the API key yourself, you must be an owner or admin of acme. Otherwise, ask one of them for a write API key and skip step 2.
    • A personal organization cannot create Boxes until a Cubicle operator allows it. After you log in, cubicle whoami --json shows boxCreateAllowed for each of your organizations.
  • macOS or Linux, on x64 or arm64, for the CLI.
  • Node.js 22 or later.

Create, use and delete a Box

  1. Install the CLI and log in.

    curl -fsSL https://api.cubicle.sh/downloads/install | sh
    cubicle login

    The installer asks before it installs the CLI in your home directory, then offers the optional tunnel, a network helper that runs as root and connects your computer to the Cubicle private network for SSH. This guide does not need the tunnel, so you can decline it. Install the CLI covers the details.

    cubicle login prints a link and a code:

    To log in, open:
      https://app.cubicle.sh/device?user_code=WDJB-MJHT
    and confirm the code WDJB-MJHT.
    Press Enter to open the browser…

    Open the link, sign in, check that the page shows the same code and choose Authorize. The CLI finishes on its own and prints Logged in as <your email>.

  2. Create a service account and an API key.

    Programs authenticate as a service account, a non-interactive member of one organization.

    cubicle service-accounts create --org acme ci
    cubicle api-keys create --org acme ci github-actions --scope write

    The first command prints created acme/ci (<ID>). The second prints the key, which starts with cbk_, followed by Store this key now; it is not shown again. Copy the key now.

    The key needs the write scope: a read key can only make GET requests. You can also create both in the Dashboard. Sign in and API keys covers scopes, expiry and the Dashboard steps.

  3. Install the SDK and set its environment.

    mkdir cubicle-quickstart && cd cubicle-quickstart
    npm init -y
    npm pkg set type=module
    npm install @cubicle/sdk
    npm install --save-dev tsx
    export CB_SDK_API_URL=https://api.cubicle.sh
    export CB_SDK_API_KEY=cbk_…   # the key from step 2

    @cubicle/sdk is ESM-only and index.ts uses top-level await, so the project needs "type": "module". new Cubicle() reads both variables.

  4. Write index.ts.

    index.ts
    import { Cubicle } from "@cubicle/sdk"
    
    const cubicle = new Cubicle()
    
    // Creates job-1 in the key's organization and waits until it is ready.
    const box = await cubicle.boxes.create({ name: "job-1" })
    
    try {
      const result = await box.exec(["uname", "-a"])
      process.stdout.write(result.stdout)
      console.log(`exit code: ${result.exitCode}`)
    } finally {
      // Deletes the Box and waits until its Node has removed it.
      await box.delete()
    }
    • create uses the API key's organization. It resolves once SSH and exec can be used, and waits up to 5 minutes by default.
    • The service account gets a grant, the per-Box permission to run commands in a Box and reach it, on every Box it creates.
    • exec runs the argument vector without a shell and resolves when the command ends.
    • delete waits up to 5 minutes, until the Box's Node, the Cubicle host that runs it, has removed it and released its resources.
  5. Run it.

    npx tsx index.ts

    On Node.js 24, node index.ts also runs it, without tsx.

    You should see the Box's kernel line, then the exit code. The kernel version varies.

    Linux box-job-1 … x86_64 GNU/Linux
    exit code: 0

If something fails

If the script stops before finally runs, for example because create timed out, the Box still exists. Delete it with the CLI and the same key, in the shell where you exported it:

CB_CLI_API_URL=$CB_SDK_API_URL CB_CLI_API_KEY=$CB_SDK_API_KEY cubicle boxes delete acme/job-1

The service account created the Box, so its grant lets it delete the Box. With your own login, cubicle boxes delete acme/job-1 works only if you are an owner or admin of acme.

ErrorCauseFix
missing_api_url or missing_api_keyCB_SDK_API_URL or CB_SDK_API_KEY is not set.Export both in the shell that runs the script.
403 insufficient_scopeThe key is a read key.Create a write key.
403 box_create_disabledThe organization cannot create Boxes.Use another organization, or ask a Cubicle operator to allow Box creation.
409 conflict: "a box named job-1 already exists"An earlier run left job-1 behind.Delete it with the command above, or choose another name.
503 capacityNo Node has room for the Box right now.Try again later.

Troubleshooting covers more errors.

Try it from the CLI

The CLI does the same with your own login. Box commands lists every option.

cubicle boxes create --org acme job-1 --wait
cubicle exec acme/job-1 -- uname -a
cubicle boxes delete acme/job-1
  • --wait waits up to 10 minutes, until SSH and exec can be used. As the Box's creator, you get the grant that exec needs.
  • cubicle exec prints the command's output and exits with its exit code. Everything after -- is the command.
  • cubicle boxes delete returns once the deletion is accepted and prints <ID> deletion pending. The Box stays in cubicle boxes list --org acme until its Node has removed it.

What you just did

  • You signed in as a person and created a service account with a write API key, the credential programs use.
  • The service account created a Box, which gave it a grant on that Box, so it could run a command there.
  • You ran a command without a shell, read its output and exit code when it finished, and deleted the Box.

Next steps

On this page