CLI
The better-compute command line 0.1.1: 189 commands.
Run better-compute help <command> for the same text in a terminal, or better-compute help --json for this manifest.
Setup
init
Write a starter configuration file
better-compute init [--config better-compute.config.ts]init writes a starter better-compute.config.ts (or the JavaScript form when --config names a .mjs or .js file): a configuration factory that uses PGlite in a local .better-compute-pglite directory for development and PostgreSQL when BETTER_COMPUTE_DATABASE_URL is set, reads the secret and base URL from the environment, shows where better-iam plugs in, and exports an empty list of project commands. It never overwrites an existing file.
| Flag | Description | Default | Environment |
|---|---|---|---|
--config PATH | Where to write the configuration (.ts, .mts, .js or .mjs) | better-compute.config.ts |
better-compute init
better-compute init --config better-compute.config.mjsmigrate
Create or upgrade the database schema and apply module migrations
better-compute migrate [--config PATH]migrate runs compute.initialize(): it checks every method's IAM action against the merged catalog and the normative method table (INVALID_CONFIG on a mismatch), then creates or upgrades the compute schema and applies every module's and plugin's migrations. Run it on every deploy before the application starts; it is idempotent.
| Flag | Description | Default | Environment |
|---|---|---|---|
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG |
better-compute migrate
BETTER_COMPUTE_DATABASE_URL=pglite:./data better-compute migratedoctor
Check the database, schema, clock, method registry and IAM wiring
better-compute doctor [--strict] [--pki PATH] [--config PATH]doctor runs compute.selfCheck() (applied migrations, btree_gist, compute_now() against the database clock, the method → action registry, and each module's own checks) and adds the CLI's findings, such as a deployment with no IAM configured, the PKI bundle, and the configuration's host export (whether the gateway role can authenticate daemons by node certificate, reach the api's pokes, tunnels and revocations, and whether host routes fit beside the API). It only reads. --strict exits non-zero (DOCTOR_FINDINGS) when any error or warning is found.
| Flag | Description | Default | Environment |
|---|---|---|---|
--strict | Exit non-zero when any error or warning is found | ||
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute doctor
better-compute doctor --strict --query "findings[].check"version
Print the better-compute version
better-compute versionversion prints the version of this command line (also --version or -v).
completion
Print a shell completion script (bash, zsh or fish)
better-compute completion SHELLcompletion prints a script that completes commands, their flags and the values of flags with choices, generated from this program's commands (a configuration's project commands included). Load it in your shell's startup file.
source <(better-compute completion bash)
source <(better-compute completion zsh)
better-compute completion fish | sourceserve
Run the API and the workers in this process
better-compute serve [--host HOST] [--port PORT] [--roles ROLES] [--no-migrate] [--config PATH]serve loads the configuration, migrates (skip with --no-migrate once a deploy step runs better-compute migrate), starts the worker roles (controllers: reconcilers and the command sweeper; scheduler; sinks: outbox dispatch; iam: IAM jobs) under their leases, and serves the API with compute.nodeHandler on --host:--port. Run several processes against one database: leases and shard ownership keep each job single-writer. --roles api serves the API only; --roles controllers,sinks runs a worker with no listener; --roles gateway runs the daemon gateway over mTLS from the configuration's host.gateway (all includes it when configured), with the report hooks of the built-in modules and tunnels when the deployment issues exec tickets. Beside the API the listener answers /healthz, /readyz, /.well-known/better-compute (the server's document, with JoinService's public keys when pki.join publishes them: the fallback bcd checks against its pins) and the host export's own routes (for example GET /watch and GET /metrics). SIGINT or SIGTERM drains the gateway first, then stops the listener and the workers, releasing their leases.
| Flag | Description | Default | Environment |
|---|---|---|---|
--host HOST | The address to listen on | 0.0.0.0 | HOST |
--port PORT | The port to listen on (0 picks a free one) | 3000 | PORT |
--roles ROLES | all, or a comma list of api, gateway and controllers, scheduler, sinks, iam | all | BETTER_COMPUTE_ROLES |
--no-migrate | Do not run migrations first | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG |
better-compute serve
better-compute serve --roles api --port 8080
better-compute serve --roles controllers,sinks,iam --no-migrate
better-compute serve --roles gateway,controllersdev
Run a local development server with no setup
better-compute dev [--host HOST] [--port PORT] [--data DIR] [--memory] [--sim N] [--sim-variant VARIANT] [--config PATH]dev runs the API and every worker role on 127.0.0.1. With a configuration file (or BETTER_COMPUTE_DATABASE_URL) it uses that deployment; without one it keeps PGlite in --data (default .better-compute/dev-db; --memory for a throwaway database) and a generated deployment secret in .better-compute/dev-secret (owner-only), so repeated runs keep their data. It always migrates first. Without IAM configured only public methods answer; see better-compute iam setup. --sim N adds a gateway on loopback cleartext HTTP/2 (sessions authenticate by a header; local development only) and N simulated machines that join the way bcd does: a join token sealed to throwaway dev JoinService keys, the Join RPC, a Session stream, diag.nvml acceptance and adoption by the real runtime. Without configured IAM, --sim starts an embedded in-memory better-iam and prints its root token; with configured IAM it acts as BETTER_COMPUTE_TOKEN, which must be a root administrator.
| Flag | Description | Default | Environment |
|---|---|---|---|
--host HOST | The address to listen on | 127.0.0.1 | |
--port PORT | The port to listen on (0 picks a free one) | 3000 | PORT |
--data DIR | Where PGlite keeps the development database (no configuration only) | .better-compute/dev-db | |
--memory | Use a throwaway in-memory database | ||
--config PATH | The configuration file (default: discovered) | BETTER_COMPUTE_CONFIG | |
--sim N | Join N simulated machines (FakeDaemons) through a loopback dev gateway (needs @better-compute/testing) | ||
--sim-variant VARIANT | Hardware of the simulated machines: hgx-h100, hgx-h100-gpu-missing, l40s, cpu | hgx-h100 |
better-compute dev
better-compute dev --memory --port 0
better-compute dev --memory --sim 8
better-compute dev --sim 4 --sim-variant l40ssim
Run the deterministic fleet simulator and check its invariants
better-compute sim [--seed SEED] [--nodes N] [--duration DURATION] [--settle DURATION] [--chaos LEVEL] [--log PATH]sim runs --nodes FakeDaemons on fake hardware against the in-memory gateway stub for --duration of simulated time, with a steady workload (diagnostics, inventory refreshes, log collection, reboots, GPU bookings) and --chaos faults (none, light, heavy: crashes, reboots, journal loss, partitions, half-open links, resets, stalls, gateway kills), then quiesces for --settle and checks invariants I1 (no double booking), I2 (at-most-once side effects), I5 (no allocation released only because its node disconnected) and I8 (usage). Nothing reads the wall clock: the same --seed prints the same digest. It exits SIM_INVARIANT_VIOLATED when an invariant fails. Needs @better-compute/testing.
| Flag | Description | Default | Environment |
|---|---|---|---|
--seed SEED | The seed | sim | |
--nodes N | Simulated nodes | 50 | |
--duration DURATION | Simulated time under workload | 10m | |
--settle DURATION | Quiet time afterwards (sweeper and replays settle) | 16m | |
--chaos LEVEL | none, light or heavy | light | |
--log PATH | Write the event log to a new file | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sim
better-compute sim --seed nightly-42 --nodes 500 --duration 1h --chaos heavysupport bundle
Write a redacted diagnostics bundle for a support request
better-compute support bundle [--out PATH] [--pki PATH] [--config PATH]support bundle collects what a support request about the control plane needs: the CLI, Node and platform versions; the configuration's shape (database kind, modules, whether IAM, PKI, tunnels and a notifier are configured; never URLs or values); doctor's findings; applied migrations; gateway and worker heartbeats; work-queue, command and IAM-inbox backlogs; and node counts by state. Environment variables appear by name only. Before anything is written, the bundle is scanned for join tokens (bcjt*), IAM tokens (biam*), JWTs, private keys, URL passwords and the deployment's own secrets, and each is replaced; a bundle in which a secret survives is refused (SUPPORT_BUNDLE_LEAK). The file is written owner-only. It only reads.
| Flag | Description | Default | Environment |
|---|---|---|---|
--out PATH | Where to write it (default better-compute-support-<time>.json; - prints it) | ||
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute support bundle
better-compute support bundle --out - > bundle.jsonAPI
api
Call any compute API method as the current token
better-compute api GROUP.METHOD [key=value ...] [--data JSON|@FILE|-] [--list] [--config PATH] [--url URL]api calls any method of the HTTP API (the same routes, envelope and permission checks as POST {basePath}/{group}/{method}) as BETTER_COMPUTE_TOKEN, in process through the configuration or against --url, and prints the result. Public methods (system.version, system.whoami) need no token; system.whoami reports the token when one is set. Build the input with --data (JSON, @file.json, or - for standard input) and key=value items: name=gpu-a sets a string, limit:=10 or labels:='["a","b"]' sets JSON, spec:=@spec.json reads a JSON file, notes=@notes.md reads a text file, resource.type=pool nests, and ids[]=a appends. Plugin methods are plugins.ID.GROUP.METHOD. api --list [GROUP] lists every route with whether it needs a token and the IAM action it is decided on.
| Flag | Description | Default | Environment |
| ----------------- | ------------------------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------- | --- | --- |
| --data JSON | @FILE | - | Request body as JSON, a JSON file, or standard input | | |
| --list | List routes (optionally of one group) instead of calling one | | |
| --config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | | BETTER_COMPUTE_CONFIG |
| --url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | | BETTER_COMPUTE_URL |
| --format FORMAT | Output as json (indented, default), compact (one line), or table | | |
| --query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) | | |
better-compute api --list
better-compute api system.version
better-compute api system.selfCheck --query "findings[].check"
better-compute api system.whoami --url https://compute.example.com
better-compute api inventory.get tenantId=tenant-acme nodeId=node_01jz0000000000000000000000
echo '{"tenantId":"tenant-acme","widgetId":"w1"}' | better-compute api plugins.acme.widgets.get --data -Access
auth login
Save a token for later commands (checked with system.whoami)
better-compute auth login [--profile NAME] [--no-verify] [--config PATH] [--url URL]auth login reads an IAM session token, API key or session JWT from standard input (or BETTER_COMPUTE_TOKEN), checks it with system.whoami against the deployment (--url, or the configuration in process; --no-verify skips the check), and saves it under --profile in better-compute's credentials file (BETTER_COMPUTE_CREDENTIALS, else %APPDATA%\better-compute or ~/.config/better-compute), written owner-only. Token commands then use it when BETTER_COMPUTE_TOKEN is unset and no better-iam session is saved. A session that better-iam's own CLI saved (better-iam login) is used without this step.
| Flag | Description | Default | Environment |
|---|---|---|---|
--profile NAME | The saved profile (default: the current one, else default) | BETTER_COMPUTE_PROFILE | |
--no-verify | Save without calling system.whoami | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute auth login --url https://compute.example.com < token.txt
BETTER_COMPUTE_TOKEN=biam_key_… better-compute auth login --profile ci --no-verifyauth status
Show which credential token commands use (never the token)
better-compute auth status [--profile NAME]auth status says where token commands get their credential, in PLAN §9.3's order: BETTER_COMPUTE_TOKEN, else better-iam's saved session (better-iam login, when @better-iam/cli is installed), else better-compute's saved profile. It lists the saved profiles without their tokens.
| Flag | Description | Default | Environment |
|---|---|---|---|
--profile NAME | The saved profile (default: the current one, else default) | BETTER_COMPUTE_PROFILE | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute auth statusauth logout
Forget a saved profile's token
better-compute auth logout [--profile NAME]auth logout removes a profile from better-compute's credentials file (the current one by default). It does not revoke the session in better-iam: run better-iam logout for that.
| Flag | Description | Default | Environment |
|---|---|---|---|
--profile NAME | The saved profile (default: the current one, else default) | BETTER_COMPUTE_PROFILE | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute auth logout
better-compute auth logout --profile cissh-cert
Get a break-glass SSH certificate for one node, next to your key
better-compute ssh-cert [COMMAND...] --tenant ID --node ID [--key PATH] [--account NAME] [--minutes N] [--connect HOST] [--ssh PROGRAM] [--config PATH] [--url URL]ssh-cert asks nodes.issueSshCert for a short-lived OpenSSH user certificate for your own public key (--key, default ~/.ssh/id_ed25519.pub, else id_ecdsa.pub) and writes it beside the key as <key>-cert.pub, where ssh -i <key> finds it. The certificate is bound to the node (principal <account>@<nodeId>): it opens that node only, as --account (default root), for --minutes (default 15, at most 60, and never past your session). It needs compute:nodes:ssh-root and a session verified with MFA. The private key never leaves your machine. Revoke it early with api nodes.revokeSshCert.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node | ||
--key PATH | Your OpenSSH public key (.pub) | ||
--account NAME | The Unix account on the node | root | |
--minutes N | Validity in minutes | 15 | |
--connect HOST | Then run ssh to the node's address with the new certificate (the command after --, or a shell) | ||
--ssh PROGRAM | The OpenSSH client for --connect | ssh | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute ssh-cert --tenant org_acme --node node_01k5w… && ssh -i ~/.ssh/id_ed25519 root@10.0.0.5
better-compute ssh-cert --tenant org_acme --node node_01k5w… --key ./ops.pub --minutes 5
better-compute ssh-cert --node node_01k5w… --connect 10.0.0.5 -- journalctl -u bcd -n 50console
Open an interactive console on a node, or an instance’s serial console
better-compute console --tenant ID [--node ID] [--instance ID] [--config PATH] [--url URL]console opens a root console on one node (--node, compute:nodes:console on the node), or the serial console of one running instance (--instance, compute:instances:exec on the instance), through tunnels.open. The session runs over the server’s tunnel WebSocket, so it needs --url (or BETTER_COMPUTE_URL). The terminal is in raw mode until the remote program exits: every key, Ctrl-C included, goes to the remote, and Ctrl-] detaches. The command exits with the remote program’s status (255 when the tunnel breaks), like ssh. Tickets are single-use and the gateway and the node verify them again; revoking your session or the delegation closes the tunnel.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node (a root shell on it) | ||
--instance ID | The instance (its serial console) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL |
better-compute console --url https://compute.example.com --tenant org_acme --node node_01k5w…
better-compute console --url https://compute.example.com --tenant org_acme --instance inst_01k5w…exec
Open an interactive shell in a running instance
better-compute exec --tenant ID --instance ID [--config PATH] [--url URL]exec opens a shell in one running instance through tunnels.open (compute:instances:exec on the instance); its node's agent runs it. The session runs over the server’s tunnel WebSocket, so it needs --url (or BETTER_COMPUTE_URL). The terminal is in raw mode until the remote program exits: every key, Ctrl-C included, goes to the remote, and Ctrl-] detaches. The command exits with the remote program’s status (255 when the tunnel breaks), like ssh. Tickets are single-use and the gateway and the node verify them again; revoking your session or the delegation closes the tunnel.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--instance ID | The instance | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL |
better-compute exec --url https://compute.example.com --tenant org_acme --instance inst_01k5w…forward
Forward a local port to a port of a running instance
better-compute forward --tenant ID --instance ID --port PORT [--local-port PORT] [--bind HOST] [--config PATH] [--url URL]forward listens on --bind (default 127.0.0.1) at --local-port (default: the same as --port; 0 picks a free one) and forwards each connection to --port on the instance through its own tcp tunnel (tunnels.open, compute:instances:exec on the instance), like ssh -L. It runs until Ctrl-C. The tunnels run over the server’s WebSocket, so it needs --url (or BETTER_COMPUTE_URL). A connection is re-authorized like any tunnel: revoking your session or the delegation closes it. Binding anything but loopback lets whoever reaches that address use your access; even on loopback, other users of this machine and web pages open in your browser can reach the port, as with ssh -L. At most 16 connections are forwarded at once, and new ones are refused while the server rate-limits your tunnels.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--instance ID | The instance | ||
--port PORT | The port on the instance | ||
--local-port PORT | The local port (default: --port; 0 picks a free one) | ||
--bind HOST | The local address to listen on | 127.0.0.1 | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL |
better-compute forward --url https://compute.example.com --tenant org_acme --instance inst_01k5w… --port 5432
better-compute forward --instance inst_01k5w… --port 8888 --local-port 0Capacity
reserve
Reserve GPUs from a pool (reservations.create)
better-compute reserve --tenant ID --pool ID --gpus N --for DURATION [--selector EXPR] [--model MODEL] [--product PRODUCT] [--nvlink] [--project ID] [--start TIME] [--lease SECONDS] [--key KEY] [--wait SECONDS] [--cpus N] [--memory GIB] [--kubernetes] [--config PATH] [--url URL]reserve asks for --gpus whole GPUs from --pool for --for, decided by better-iam as compute:reservations:create on the reservation draft and placed by the pool's placer (PLAN.md §3.4, §10.3). --selector takes the shorthand gpuProduct in (H100-SXM5-80GB), vramGiB >= 80; --model and --product add a gpuModel or gpuProduct match. It waits up to --wait seconds for the placement and prints the reservation, whose binding lists the booked GPU UUIDs once active. Every run sends a new idempotency key unless --key is given: repeat the command with the same --key to retry safely.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool to reserve from (pool_…) | ||
--gpus N | Whole GPUs to reserve | ||
--for DURATION | How long: 30m, 8h, 7d | ||
--selector EXPR | Device selector shorthand, e.g. "vramGiB >= 80" | ||
--model MODEL | GPU model family, e.g. H100 | ||
--product PRODUCT | GPU product, e.g. H100-SXM5-80GB | ||
--nvlink | All GPUs must share one NVLink domain | ||
--project ID | Project to account the reservation to (prj_…) | ||
--start TIME | Start later: ISO 8601 time or +DURATION (default now) | ||
--lease SECONDS | Renewable lease: released unless renewed within this many seconds | ||
--key KEY | Idempotency key, to retry an earlier request | ||
--wait SECONDS | How long to wait for the placement | 20 | |
--cpus N | Host CPUs to book with the GPUs (default: the pool's per-GPU share) | ||
--memory GIB | Host memory in GiB to book with the GPUs (default: the pool's per-GPU share) | ||
--kubernetes | Give the GPUs to the node's kubelet (pools that join a Kubernetes cluster) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute reserve --pool pool_01k… --gpus 4 --for 8h
better-compute reserve --pool pool_01k… --gpus 2 --for 8h --cpus 32 --memory 256 --kubernetes
better-compute reserve --pool pool_01k… --gpus 8 --for 3d --model H100 --nvlink --selector "vramGiB >= 80"
better-compute reserve --pool pool_01k… --gpus 2 --for 1h --start +2h --key nightly-2026-09-24release
Release a reservation early (reservations.release)
better-compute release RESERVATION --tenant ID [--cancel] [--config PATH] [--url URL]release ends an active or placed reservation now: its bookings are truncated, the GPUs return to the pool and billing stops at the release time. A reservation that has not started yet can be withdrawn with --cancel instead (reservations.cancel).
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--cancel | Withdraw a reservation that has not started | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute release rsv_01k…
better-compute release rsv_01k… --cancelextend
Extend a reservation (reservations.extend)
better-compute extend RESERVATION --tenant ID [--by DURATION] [--until TIME] [--renew] [--key KEY] [--config PATH] [--url URL]extend moves the end of a reservation later, by --by or to --until. It is admitted like a new reservation: better-iam decides compute:reservations:extend on the total duration after the change, so policy caps also bound extensions, and the booking must still be free. With --renew it instead renews a leased reservation (reservations.renew).
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--by DURATION | Extend by this much: 30m, 4h, 1d | ||
--until TIME | Extend to this time: ISO 8601 or +DURATION | ||
--renew | Renew the lease of a renewable reservation instead | ||
--key KEY | Idempotency key, to retry an earlier request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute extend rsv_01k… --by 4h
better-compute extend rsv_01k… --renewreservations list
List the tenant’s reservations (reservations.list)
better-compute reservations list --tenant ID [--state STATE] [--pool ID] [--limit N] [--cursor ID] [--config PATH] [--url URL]List the tenant’s reservations (reservations.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--state STATE | Only this state: active, placed, pending, … | ||
--pool ID | Only this pool | ||
--limit N | Page size | ||
--cursor ID | Continue after this reservation | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute reservations list --state active
better-compute reservations list --format jsonreservations get
Show one reservation, with its binding (reservations.get)
better-compute reservations get RESERVATION --tenant ID [--config PATH] [--url URL]Show one reservation, with its binding (reservations.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute reservations get rsv_01k… --query bindingpools list
List the pools the tenant owns or is offered (pools.list)
better-compute pools list --tenant ID [--config PATH] [--url URL]List the pools the tenant owns or is offered (pools.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pools listcapacity
Show free and allocated capacity: a summary, or one pool (capacity.summary, capacity.byPool)
better-compute capacity --tenant ID [--pool ID] [--preview] [--gpus N] [--for DURATION] [--selector EXPR] [--cpus N] [--memory GIB] [--kubernetes] [--config PATH] [--url URL]capacity prints what the tenant can see: per pool and per GPU model, total, allocatable, allocated, reserved and available. With --pool it prints that pool's rollup. With --preview and a --gpus request it asks where such a reservation would fit right now (capacity.preview) without booking anything.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | One pool | ||
--preview | Preview a placement (needs --pool, --gpus and --for) | ||
--gpus N | GPUs for --preview | ||
--for DURATION | Duration for --preview | ||
--selector EXPR | Selector shorthand for --preview | ||
--cpus N | Host CPUs to book with the GPUs (default: the pool's per-GPU share) | ||
--memory GIB | Host memory in GiB to book with the GPUs (default: the pool's per-GPU share) | ||
--kubernetes | Give the GPUs to the node's kubelet (pools that join a Kubernetes cluster) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute capacity
better-compute capacity --pool pool_01k…
better-compute capacity --preview --pool pool_01k… --gpus 8 --for 1d --selector "vramGiB >= 80"Sandboxes
sandbox create
Create a sandbox from a template (sandboxes.create)
better-compute sandbox create --tenant ID --template ID [--ttl DURATION] [--from-snapshot ID] [--wait SECONDS] [--key KEY] [--config PATH] [--url URL]sandbox create starts a sandbox from --template (sbxt_…), claimed from the template's warm pool when it keeps one, decided by better-iam as compute:sandboxes:create. It lives --ttl (default: the template's default, at most its maximum) and is deleted then unless extended. --from-snapshot restores a snapshot of yours instead of booting the image. It waits up to --wait seconds (default 30) for the sandbox to leave starting and prints it. Every run sends a new idempotency key unless --key is given: repeat with the same --key to retry safely.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--template ID | The template (sbxt_…) | ||
--ttl DURATION | How long it lives: 15m, 2h | ||
--from-snapshot ID | Restore this snapshot (snap_…) | ||
--wait SECONDS | Wait this long for it to start | 30 | |
--key KEY | Idempotency key, to retry the same request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox create --template sbxt_01k5w… --ttl 30m
better-compute sandbox create --template sbxt_01k5w… --from-snapshot snap_01k5w…sandbox list
List sandboxes: yours, or the tenant’s with --all (sandboxes.list)
better-compute sandbox list --tenant ID [--all] [--deleted] [--template ID] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List sandboxes: yours, or the tenant’s with --all (sandboxes.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--all | Every sandbox of the tenant, not only yours | ||
--deleted | Include deleted sandboxes | ||
--template ID | Only this template’s (sbxt_…) | ||
--limit N | Page size (at most 200) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox list
better-compute sandbox list --all --query "items[*].id"sandbox get
Show a sandbox, its expiry and its snapshots (sandboxes.get)
better-compute sandbox get SANDBOX --tenant ID [--config PATH] [--url URL]Show a sandbox, its expiry and its snapshots (sandboxes.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox get sbx_01k5w…sandbox extend
Move a sandbox’s expiry (sandboxes.extend)
better-compute sandbox extend SANDBOX --tenant ID [--by DURATION] [--until TIME] [--config PATH] [--url URL]sandbox extend adds --by to the current expiry, or sets it to --until (ISO 8601, epoch ms or +DURATION from now), within the template's maximum lifetime. Decided as compute:sandboxes:update on the sandbox.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--by DURATION | Add this to the expiry: 30m, 2h | ||
--until TIME | The new expiry | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox extend sbx_01k5w… --by 30m
better-compute sandbox extend sbx_01k5w… --until +2hsandbox snapshot
Snapshot a sandbox, memory included unless --no-memory (sandboxes.snapshot)
better-compute sandbox snapshot SANDBOX --tenant ID [--no-memory] [--keep] [--key KEY] [--config PATH] [--url URL]sandbox snapshot asks the sandbox's host for its instance's state; the snapshot is pending until the host reports it. Snapshots go with the sandbox unless --keep. Restore one with sandbox create --from-snapshot.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--no-memory | Disk only (not a running state) | ||
--keep | Keep it after the sandbox is deleted | ||
--key KEY | Idempotency key, to retry the same request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox snapshot sbx_01k5w… --keepsandbox delete
Delete a sandbox now (sandboxes.delete)
better-compute sandbox delete SANDBOX --tenant ID [--config PATH] [--url URL]Delete a sandbox now (sandboxes.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox delete sbx_01k5w…sandbox exec
Run a command (or a shell) in a sandbox over SSH through a tunnel (sandboxes.exec)
better-compute sandbox exec SANDBOX [COMMAND...] --tenant ID [--key PATH] [--minutes N] [--ssh PROGRAM] [--accept-host-key] [--config PATH] [--url URL]sandbox exec asks sandboxes.exec for a short-lived SSH certificate for your own key (--key, default ~/.ssh/id_ed25519; its .pub is sent, the private key never leaves this machine) and a single-use tunnel ticket to the sandbox's instance, then runs your OpenSSH client (--ssh, default ssh) through that tunnel: the command after --, or a login shell. There is no agent in the guest; its sshd trusts the sandbox CA for <account>@<instance>. The certificate and a known_hosts file for this one connection live in a temporary directory that is removed afterwards. It exits with ssh's status. Needs --url (tunnels run over the server's WebSocket) and a signed-in session.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--key PATH | Your private key (its .pub beside it is sent) | ||
--minutes N | Certificate lifetime in minutes | 10 | |
--ssh PROGRAM | The OpenSSH client to run | ssh | |
--accept-host-key | Connect although the guest's host key is not certified (older guests, or an expired host certificate): accepted on first use | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL |
better-compute sandbox exec sbx_01k5w… -- uname -a
better-compute sandbox exec sbx_01k5w…sandbox-template create
Create a sandbox template for the tenant (sandboxTemplates.create)
better-compute sandbox-template create --tenant ID --name NAME --pool ID [--runtime ID] [--flavor NAME] [--image ID] [--user-data FILE] [--default-ttl DURATION] [--max-ttl DURATION] [--warm-min N] [--warm-max N] [--env NAME=REF,…] [--network MODE] [--volumes NAME:/PATH[:ro],…] [--config PATH] [--url URL]sandbox-template create defines what sandbox create --template starts: --pool, --flavor and --image (and the pool's --runtime), the default and longest lifetimes, a warm pool kept ready (--warm-min/--warm-max), user data from a file, environment variables from secret references and the network mode. Decided as compute:sandboxes:manage on the tenant.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--name NAME | The template name | ||
--pool ID | The pool its instances run in (pool_…) | ||
--runtime ID | The pool's runtime driver (checked against it) | ||
--flavor NAME | The instance flavor (the pool offers it) | ||
--image ID | The image | ||
--user-data FILE | cloud-init user data for every sandbox, from a file | ||
--default-ttl DURATION | Default lifetime: 30m, 2h | ||
--max-ttl DURATION | Longest lifetime a sandbox may be given or extended to | ||
--warm-min N | Warm instances kept ready | ||
--warm-max N | At most this many warm instances | ||
--env NAME=REF,… | Environment from secret references: NAME=secret://<tenant>/<id>, comma-separated | ||
--network MODE | What sandboxes may reach (default egress) | ||
--volumes NAME:/PATH[:ro],… | Persistent volumes (agent memory) every sandbox mounts, in order; "" removes them | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-template create --name python --pool pool_01k5w… --flavor small --image img_01k5w… --warm-min 2 --max-ttl 4hsandbox-template update
Change a sandbox template (sandboxTemplates.update)
better-compute sandbox-template update TEMPLATE --tenant ID [--flavor NAME] [--image ID] [--user-data FILE] [--default-ttl DURATION] [--max-ttl DURATION] [--warm-min N] [--warm-max N] [--env NAME=REF,…] [--network MODE] [--volumes NAME:/PATH[:ro],…] [--no-user-data] [--config PATH] [--url URL]sandbox-template update changes only the fields given; --no-user-data removes the user data. Sandboxes already running keep what they started with; the warm pool is refilled from the new definition.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--flavor NAME | The instance flavor (the pool offers it) | ||
--image ID | The image | ||
--user-data FILE | cloud-init user data for every sandbox, from a file | ||
--default-ttl DURATION | Default lifetime: 30m, 2h | ||
--max-ttl DURATION | Longest lifetime a sandbox may be given or extended to | ||
--warm-min N | Warm instances kept ready | ||
--warm-max N | At most this many warm instances | ||
--env NAME=REF,… | Environment from secret references: NAME=secret://<tenant>/<id>, comma-separated | ||
--network MODE | What sandboxes may reach (default egress) | ||
--volumes NAME:/PATH[:ro],… | Persistent volumes (agent memory) every sandbox mounts, in order; "" removes them | ||
--no-user-data | Remove the user data | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-template update sbxt_01k5w… --warm-min 4 --image img_01k5w…sandbox-template delete
Delete a sandbox template (sandboxTemplates.delete)
better-compute sandbox-template delete TEMPLATE --tenant ID [--config PATH] [--url URL]Delete a sandbox template (sandboxTemplates.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-template delete sbxt_01k5w…sandbox templates
List the tenant’s sandbox templates and their warm pools (sandboxTemplates.list)
better-compute sandbox templates --tenant ID [--config PATH] [--url URL]List the tenant’s sandbox templates and their warm pools (sandboxTemplates.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox templates --format tablesandbox-volume create
Create a persistent volume (agent memory) on a pool (sandboxVolumes.create)
better-compute sandbox-volume create --tenant ID --pool ID --name NAME --size GIB [--key KEY] [--config PATH] [--url URL]sandbox-volume create books --size GiB of disk on one host of --pool; sandboxes of templates that mount it (sandbox-template --volumes) run on that host and keep its data across runs. It is billed until deleted. Repeat with the same --key to retry safely.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool (pool_…) | ||
--name NAME | A name unique in the tenant | ||
--size GIB | Size in GiB | ||
--key KEY | Idempotency key, to retry the same request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-volume create --pool pool_01k5w… --name agent-notes --size 20sandbox-volume list
List the tenant’s persistent volumes (sandboxVolumes.list)
better-compute sandbox-volume list --tenant ID [--pool ID] [--deleted] [--all] [--config PATH] [--url URL]List the tenant’s persistent volumes (sandboxVolumes.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | Only this pool’s (pool_…) | ||
--deleted | Include deleted volumes | ||
--all | Every volume of the tenant you may see, not only yours | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-volume list --format tablesandbox-volume get
Show a persistent volume (sandboxVolumes.get)
better-compute sandbox-volume get VOLUME --tenant ID [--config PATH] [--url URL]Show a persistent volume (sandboxVolumes.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-volume get vol_01k5w…sandbox-volume resize
Grow a persistent volume (sandboxVolumes.resize)
better-compute sandbox-volume resize VOLUME --tenant ID --size GIB [--config PATH] [--url URL]sandbox-volume resize grows the volume to --size GiB; volumes never shrink.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--size GIB | The new size in GiB | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-volume resize vol_01k5w… --size 40sandbox-volume delete
Delete a persistent volume and wipe its data (sandboxVolumes.delete)
better-compute sandbox-volume delete VOLUME --tenant ID [--config PATH] [--url URL]Delete a persistent volume and wipe its data (sandboxVolumes.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-volume delete vol_01k5w…sandbox-snapshot list
List sandbox snapshots, kept ones of deleted sandboxes too (sandboxSnapshots.list)
better-compute sandbox-snapshot list --tenant ID [--all] [--sandbox ID] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List sandbox snapshots, kept ones of deleted sandboxes too (sandboxSnapshots.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--all | Every snapshot of the tenant, not only yours | ||
--sandbox ID | Only this sandbox’s (sbx_…) | ||
--limit N | Page size (at most 200) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-snapshot list --sandbox sbx_01k5w…sandbox-snapshot get
Show a sandbox snapshot and its state (sandboxSnapshots.get)
better-compute sandbox-snapshot get SNAPSHOT --tenant ID [--config PATH] [--url URL]Show a sandbox snapshot and its state (sandboxSnapshots.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-snapshot get snap_01k5w…sandbox-snapshot delete
Delete a sandbox snapshot (sandboxSnapshots.delete)
better-compute sandbox-snapshot delete SNAPSHOT --tenant ID [--config PATH] [--url URL]Delete a sandbox snapshot (sandboxSnapshots.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sandbox-snapshot delete snap_01k5w…Nodes
nodes list
List the tenant’s nodes (nodes.list)
better-compute nodes list --tenant ID [--pool ID] [--site ID] [--cordoned] [--state STATE] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List the tenant’s nodes (nodes.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | Only this pool’s | ||
--site ID | Only this site’s (site_…) | ||
--cordoned | Only cordoned nodes | ||
--state STATE | Only nodes in this provisioning state | ||
--limit N | Page size (at most 50) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute nodes list --pool h100-eu
better-compute nodes list --cordoned --format jsonnodes get
Show one node: its state, labels, conditions and session (nodes.get)
better-compute nodes get NODE --tenant ID [--config PATH] [--url URL]Show one node: its state, labels, conditions and session (nodes.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute nodes get node_01k5w…
better-compute nodes get node_01k5w… --query conditionsnodes events
List a node’s events, newest first (nodes.events)
better-compute nodes events NODE --tenant ID [--type TYPE] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List a node’s events, newest first (nodes.events)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--type TYPE | Only events of this type (node.cordoned, gpu.xid, …) | ||
--limit N | Page size (at most 200) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute nodes events node_01k5w… --type gpu.xidnodes cordon
Stop placing new work on a node (nodes.cordon)
better-compute nodes cordon NODE --tenant ID [--reason TEXT] [--if-version N] [--config PATH] [--url URL]nodes cordon keeps the scheduler from placing anything new on the node; what runs there keeps running. Decided as compute:nodes:cordon. --if-version makes it conditional on the version nodes get printed.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--reason TEXT | Why (recorded in the node’s events) | ||
--if-version N | Only if the node is still at this version (nodes.get’s version) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute nodes cordon node_01k5w… --reason "disk replacement"nodes uncordon
Let the scheduler place work on a node again (nodes.uncordon)
better-compute nodes uncordon NODE --tenant ID [--reason TEXT] [--if-version N] [--config PATH] [--url URL]nodes uncordon undoes nodes cordon. Decided as compute:nodes:cordon.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--reason TEXT | Why (recorded in the node’s events) | ||
--if-version N | Only if the node is still at this version (nodes.get’s version) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute nodes uncordon node_01k5w… --reason "disk replacement"nodes drain
Cordon a node and move its work off (nodes.drain)
better-compute nodes drain NODE --tenant ID [--reason TEXT] [--if-version N] [--config PATH] [--url URL]nodes drain cordons the node and hands its allocations to the Drain controller, which releases them within the pool’s disruption budget. Decided as compute:nodes:drain; follow it with nodes events (node.draining, then the releases).
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--reason TEXT | Why (recorded in the node’s events) | ||
--if-version N | Only if the node is still at this version (nodes.get’s version) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute nodes drain node_01k5w… --reason "disk replacement"nodes label
Set or remove a node’s labels (nodes.label)
better-compute nodes label NODE --tenant ID [--set KEY=VALUE,…] [--remove KEY,…] [--if-version N] [--config PATH] [--url URL]nodes label sets labels from --set KEY=VALUE,… and removes the keys in --remove KEY,…; selectors (reservations, pools) match on them. Decided as compute:nodes:update.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--set KEY=VALUE,… | Labels to set | ||
--remove KEY,… | Label keys to remove | ||
--if-version N | Only if the node is still at this version (nodes.get’s version) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute nodes label node_01k5w… --set rack=r12,fabric=ib-a --remove oldnodes taint
Add or remove a node’s taints (nodes.taint)
better-compute nodes taint NODE --tenant ID [--add TAINT,…] [--remove TAINT,…] [--if-version N] [--config PATH] [--url URL]nodes taint adds the taints in --add and removes those in --remove (comma-separated). A taint joins the node’s NoSchedule reasons as taint:<taint>, so the scheduler places nothing new there until it is removed. Decided as compute:nodes:update.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--add TAINT,… | Taints to add | ||
--remove TAINT,… | Taints to remove | ||
--if-version N | Only if the node is still at this version (nodes.get’s version) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute nodes taint node_01k5w… --add gpu=degraded:NoSchedulenodes delete
Remove a retired or cordoned adopted node for good (nodes.delete)
better-compute nodes delete NODE --tenant ID [--reason TEXT] [--if-version N] [--yes] [--config PATH] [--url URL]nodes delete tombstones a node that is retired, a cordoned adopted node (cordon it first), or one that never got past adoption or enrollment, once it holds no allocation. Its certificates are revoked and its hardware key and attestor bindings (e.g. a TPM) are freed, so the machine can join again as a new node: after a TPM swap, cordon, delete, then run bcd join --reset --yes and bcd join on the machine. It cannot be undone, so it needs --yes. Decided as compute:nodes:delete.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--reason TEXT | Why (recorded in the node’s events) | ||
--if-version N | Only if the node is still at this version (nodes.get’s version) | ||
--yes | Confirm: the node is removed for good | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute nodes delete node_01k5w… --reason "TPM replaced" --yesjoin-tokens create
Create a join token for a pool: what bcd join presents (joinTokens.create)
better-compute join-tokens create --tenant ID --pool ID --ttl DURATION [--max-uses N] [--allow-reclaim] [--hosted WHERE] [--expect-product-uuid UUID] [--expect-serial SERIAL] [--expect-mac MAC] [--expect-gpu-uuid GPU-…] [--out PATH] [--key KEY] [--config PATH] [--url URL]join-tokens create mints a token that lets up to --max-uses machines (default 1) join --pool for --ttl (60s to 24h). --expect-* bind it to one machine's identity (product UUID, serial, MAC or GPU UUID). --hosted kubernetes marks it for bcd as a DaemonSet (deploy/kubernetes): the cluster's admins have root on its machines, so they join tenant-controlled unless the pool's policy.kubernetes.platformOperated is true. The token is printed once and never again: with --out it goes to a new file (0600, never overwritten) instead of the output, to hand to the server out of band (the install script reads BCD_JOIN_TOKEN or stdin). Decided as compute:join-tokens:create.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool machines join | ||
--ttl DURATION | How long it is valid: 30m, 2h (at most 24h) | ||
--max-uses N | Machines it admits (default 1) | ||
--allow-reclaim | May re-admit a machine the pool already knew | ||
--hosted WHERE | For bcd as a DaemonSet on a Kubernetes cluster: its nodes join tenant-controlled unless the pool says the platform operates the cluster | ||
--expect-product-uuid UUID | Only the machine with this SMBIOS product UUID | ||
--expect-serial SERIAL | Only the machine with this serial number | ||
--expect-mac MAC | Only the machine with this MAC address | ||
--expect-gpu-uuid GPU-… | Only the machine with this GPU | ||
--out PATH | Write the token to this new file instead of printing it | ||
--key KEY | Idempotency key, to retry the same request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute join-tokens create --pool h100-eu --ttl 2h --max-uses 8 --out ./join-token
better-compute join-tokens create --pool h100-eu --ttl 30m --expect-serial SN12345
better-compute join-tokens create --pool k8s-gpu --ttl 2h --max-uses 16 --hosted kubernetes --out ./join-tokenjoin-tokens list
List a pool’s join tokens, never their secrets (joinTokens.list)
better-compute join-tokens list --tenant ID --pool ID [--all] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List a pool’s join tokens, never their secrets (joinTokens.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool | ||
--all | Also revoked, expired and used-up tokens | ||
--limit N | Page size (at most 200) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute join-tokens list --pool h100-eujoin-tokens revoke
Revoke a join token before it expires (joinTokens.revoke)
better-compute join-tokens revoke TOKEN --tenant ID --pool ID [--config PATH] [--url URL]Revoke a join token before it expires (joinTokens.revoke)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute join-tokens revoke jt_01k5w… --pool h100-eujoin-requests list
List a pool’s join requests, pending by default (joinRequests.list)
better-compute join-requests list --tenant ID --pool ID [--state STATE] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List a pool’s join requests, pending by default (joinRequests.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool | ||
--state STATE | Which requests (default pending) | ||
--limit N | Page size (at most 200) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute join-requests list --pool h100-eujoin-requests approve
Let a machine that asked join the pool (joinRequests.approve)
better-compute join-requests approve REQUEST --tenant ID --pool ID [--reason TEXT] [--ttl SECONDS] [--config PATH] [--url URL]join-requests approve admits the machine behind the request into --pool; the approval waits --ttl seconds (default 3600) for the machine to retry. Check its claims (join-requests list) first: approving is what makes an unknown machine a node. Decided as compute:join-tokens:create.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool | ||
--reason TEXT | Recorded on the request | ||
--ttl SECONDS | How long it may join | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute join-requests approve jreq_01k5w… --pool h100-eujoin-requests reject
Turn a machine’s join request down (joinRequests.reject)
better-compute join-requests reject REQUEST --tenant ID --pool ID [--reason TEXT] [--config PATH] [--url URL]Turn a machine’s join request down (joinRequests.reject)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool | ||
--reason TEXT | Recorded on the request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute join-requests reject jreq_01k5w… --pool h100-euinventory get
Show a node’s current hardware inventory (inventory.get)
better-compute inventory get NODE --tenant ID [--config PATH] [--url URL]Show a node’s current hardware inventory (inventory.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute inventory get node_01k5w… --query gpusinventory history
List a node’s inventory snapshots, newest first (inventory.history)
better-compute inventory history NODE --tenant ID [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List a node’s inventory snapshots, newest first (inventory.history)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--limit N | Page size (at most 100) | ||
--cursor CURSOR | The cursor of the previous page (inv_…) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute inventory history node_01k5w…inventory diff
Show what changed in a node’s hardware between two snapshots (inventory.diff)
better-compute inventory diff NODE --tenant ID [--from SNAPSHOT] [--to SNAPSHOT] [--config PATH] [--url URL]inventory diff compares --from and --to (snapshot ids from inventory history, or inventory digests). Without --to it is the latest snapshot, without --from the one before --to.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--from SNAPSHOT | The older snapshot (inv_…) or digest | ||
--to SNAPSHOT | The newer snapshot (inv_…) or digest | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute inventory diff node_01k5w…site-tokens create
Create a token a site agent joins a site with (siteTokens.create)
better-compute site-tokens create --tenant ID --site ID --ttl SECONDS [--max-uses N] [--out PATH] [--key KEY] [--config PATH] [--url URL]site-tokens create mints a token for up to --max-uses site agents (default 1) to join --site within --ttl seconds. It is printed once: with --out it goes to a new 0600 file instead. Decided as compute:sites:manage.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--site ID | The site (site_…) | ||
--ttl SECONDS | How long it is valid | ||
--max-uses N | Site agents it admits (default 1) | ||
--out PATH | Write the token to this new file instead of printing it | ||
--key KEY | Idempotency key, to retry the same request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute site-tokens create --site site_01k5w… --ttl 3600 --out ./site-tokensite-tokens revoke
Revoke a site token (siteTokens.revoke)
better-compute site-tokens revoke TOKEN --tenant ID --site ID [--config PATH] [--url URL]Revoke a site token (siteTokens.revoke)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--site ID | The site | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute site-tokens revoke jt_01k5w… --site site_01k5w…Instances
instances list
List instances: yours, or the tenant’s with --all (instances.list)
better-compute instances list --tenant ID [--all] [--state STATE] [--pool ID] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List instances: yours, or the tenant’s with --all (instances.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--all | Every instance of the tenant, not only yours | ||
--state STATE | Only instances in this state | ||
--pool ID | Only this pool’s | ||
--limit N | Page size (at most 200) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute instances list
better-compute instances list --all --state runninginstances get
Show one instance (instances.get)
better-compute instances get INSTANCE --tenant ID [--config PATH] [--url URL]Show one instance (instances.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute instances get inst_01k5w…instances create
Create an instance in a pool (instances.create)
better-compute instances create --tenant ID --pool ID --flavor NAME --image ID [--project ID] [--ssh-key PATH,…] [--user-data FILE|secret://…] [--stopped] [--wait SECONDS] [--key KEY] [--config PATH] [--url URL]instances create boots --image with --flavor in --pool, decided as compute:instances:create. --ssh-key reads OpenSSH public keys from files (comma-separated paths; every non-empty line is a key), --user-data cloud-init from a file, or a secret://<tenant>/<id> reference. --stopped creates it without starting it. It waits up to --wait seconds (default 30) for the instance to settle. Every run sends a new idempotency key unless --key is given: repeat with the same --key to retry safely.
| Flag | Description | Default | Environment |
| ------------------ | ------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ----------------------- | --- |
| --tenant ID | The tenant acting (the caller’s organization) | | BETTER_COMPUTE_TENANT |
| --pool ID | The pool | | |
| --flavor NAME | The flavor (the pool offers it) | | |
| --image ID | The image to boot | | |
| --project ID | The project it belongs to | | |
| --ssh-key PATH,… | Files of OpenSSH public keys to authorize | | |
| --user-data FILE | secret://… | cloud-init user data (at most 32 KiB) | | |
| --stopped | Create it stopped | | |
| --wait SECONDS | Wait this long for it to settle | 30 | |
| --key KEY | Idempotency key, to retry the same request | | |
| --config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | | BETTER_COMPUTE_CONFIG |
| --url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | | BETTER_COMPUTE_URL |
| --format FORMAT | Output as json (indented, default), compact (one line), or table | | |
| --query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) | | |
better-compute instances create --pool vps-eu --flavor g1.small --image img_01k5w… --ssh-key ~/.ssh/id_ed25519.pubinstances start
Start a stopped instance (instances.start)
better-compute instances start INSTANCE --tenant ID [--config PATH] [--url URL]Start a stopped instance (instances.start)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute instances start inst_01k5w…instances stop
Stop a running instance (instances.stop)
better-compute instances stop INSTANCE --tenant ID [--config PATH] [--url URL]Stop a running instance (instances.stop)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute instances stop inst_01k5w…instances delete
Delete an instance and its disks (instances.delete)
better-compute instances delete INSTANCE --tenant ID [--config PATH] [--url URL]Delete an instance and its disks (instances.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute instances delete inst_01k5w…instances resize
Move an instance to another flavor (instances.resize)
better-compute instances resize INSTANCE --tenant ID --flavor NAME [--config PATH] [--url URL]Move an instance to another flavor (instances.resize)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--flavor NAME | The new flavor | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute instances resize inst_01k5w… --flavor g1.largeEvents
events list
List the tenant’s events, newest first (events.list)
better-compute events list --tenant ID [--type TYPE] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List the tenant’s events, newest first (events.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--type TYPE | Only events of this type (node.cordoned, reservation.placed, …) | ||
--limit N | Page size (at most 500) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute events list --type node.draining
better-compute events list --query "items[*].type"events watch
Follow the tenant’s events as they happen, one JSON line each (GET /watch)
better-compute events watch --tenant ID [--types PATTERN,…] [--since CURSOR] [--count N] [--path PATH] [--config PATH] [--url URL]events watch follows the host's server-sent events route (--path, default /watch; the console app serves /api/compute/watch) as BETTER_COMPUTE_TOKEN, so it needs --url. Each event is printed as one line of JSON with its sequence, the cursor: pass the last one to --since to resume where a previous run stopped. It reconnects after a broken connection, resuming from the last event, until Ctrl-C, --count events, or a refusal: a revoked session or a withdrawn compute:events:read ends it.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--types PATTERN,… | Event type patterns, comma-separated (node.*, reservation.placed); default all | ||
--since CURSOR | Resume after this event (a printed sequence) | ||
--count N | Stop after N events | ||
--path PATH | The watch route on the server | /watch | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL |
better-compute events watch --url https://compute.example.com --types "node.*,reservation.*"
better-compute events watch --url https://compute.example.com --since 184467.12 --count 100Operations
releases register
Register a signed bcd release manifest for rollouts (releases.register)
better-compute releases register MANIFEST --tenant ID [--config PATH] [--url URL]releases register sends a published manifest.json ({ manifest, signatures }) as it is; the server checks the signatures against its release keys. Decided as compute:fleet:admin.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute releases register ./dist/manifest.jsonreleases list
List the registered bcd releases (releases.list)
better-compute releases list --tenant ID [--config PATH] [--url URL]List the registered bcd releases (releases.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute releases listrollouts create
Roll a registered bcd release out in waves (rollouts.create)
better-compute rollouts create --tenant ID --version SEMVER [--pools ID,…] [--waves PCT,…] [--max-failure-ratio RATIO] [--soak DURATION] [--upgrade-timeout DURATION] [--key KEY] [--config PATH] [--url URL]rollouts create upgrades the nodes of --pools (default: every pool the tenant owns) to --version in cumulative --waves of percentages (default 1,10,50,100). Each wave soaks --soak (default 10m) before the next, a node has --upgrade-timeout (default 15m) to come back on the new version, and more than --max-failure-ratio failed nodes (default 0.05) pause the rollout. Decided as compute:fleet:admin.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--version SEMVER | The registered release | ||
--pools ID,… | The pools to upgrade (pool_…) | ||
--waves PCT,… | Cumulative percentages ending at 100 | ||
--max-failure-ratio RATIO | The failed share that pauses it (0–1) | ||
--soak DURATION | How long each wave soaks | ||
--upgrade-timeout DURATION | How long a node has to come back | ||
--key KEY | Idempotency key, to retry the same request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute rollouts create --version 0.9.1 --waves 5,25,100 --soak 30mrollouts list
List rollouts (rollouts.list)
better-compute rollouts list --tenant ID [--config PATH] [--url URL]List rollouts (rollouts.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute rollouts listrollouts get
Show a rollout: its waves and per-node progress (rollouts.get)
better-compute rollouts get ROLLOUT --tenant ID [--config PATH] [--url URL]Show a rollout: its waves and per-node progress (rollouts.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute rollouts get rollout_01k5w…rollouts pause
Pause a rollout before its next wave (rollouts.pause)
better-compute rollouts pause ROLLOUT --tenant ID [--reason TEXT] [--config PATH] [--url URL]Pause a rollout before its next wave (rollouts.pause)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--reason TEXT | Recorded on the rollout | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute rollouts pause rollout_01k5w… --reason "XIDs after wave 2"rollouts resume
Resume a paused rollout (rollouts.resume)
better-compute rollouts resume ROLLOUT --tenant ID [--config PATH] [--url URL]Resume a paused rollout (rollouts.resume)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute rollouts resume rollout_01k5w…rollouts abort
Stop a rollout for good, optionally rolling nodes back (rollouts.abort)
better-compute rollouts abort ROLLOUT --tenant ID [--reason TEXT] [--rollback] [--config PATH] [--url URL]rollouts abort ends the rollout: no further node is upgraded. --rollback also swaps back the nodes whose upgrade is not confirmed yet. A node that confirmed the new release keeps it (it never goes below its release floor), so a bad release is undone by rolling a newer one forward.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--reason TEXT | Recorded on the rollout | ||
--rollback | Also swap back upgrades not confirmed yet | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute rollouts abort rollout_01k5w… --rollback --reason "boot loop on H100 nodes"workflows list
List a node’s workflows, newest first (workflows.list)
better-compute workflows list --tenant ID --node ID [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List a node’s workflows, newest first (workflows.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node (node_…) | ||
--limit N | Page size (at most 100) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute workflows list --node node_01k5w…workflows get
Show a workflow and its steps (workflows.get)
better-compute workflows get WORKFLOW --tenant ID --node ID [--config PATH] [--url URL]Show a workflow and its steps (workflows.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node (node_…) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute workflows get wf_01k5w… --node node_01k5w… --query stepsworkflows abort
Abort a workflow: pending steps are cancelled, its cleanup still runs (workflows.abort)
better-compute workflows abort WORKFLOW --tenant ID --node ID [--reason TEXT] [--config PATH] [--url URL]Abort a workflow: pending steps are cancelled, its cleanup still runs (workflows.abort)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node (node_…) | ||
--reason TEXT | Recorded on the workflow | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute workflows abort wf_01k5w… --node node_01k5w…workflows pause
Pause a workflow: the step in flight finishes, no further one starts (workflows.pause)
better-compute workflows pause WORKFLOW --tenant ID --node ID [--config PATH] [--url URL]Pause a workflow: the step in flight finishes, no further one starts (workflows.pause)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node (node_…) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute workflows pause wf_01k5w… --node node_01k5w…workflows resume
Resume a paused workflow (workflows.resume)
better-compute workflows resume WORKFLOW --tenant ID --node ID [--config PATH] [--url URL]Resume a paused workflow (workflows.resume)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node (node_…) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute workflows resume wf_01k5w… --node node_01k5w…workflows retry
Retry a failed workflow, from a step (workflows.retry)
better-compute workflows retry WORKFLOW --tenant ID --node ID [--from-step STEP] [--config PATH] [--url URL]Retry a failed workflow, from a step (workflows.retry)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node (node_…) | ||
--from-step STEP | Start here (default: the first main step that did not succeed) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute workflows retry wf_01k5w… --node node_01k5w…commands list
List the commands queued for a node, newest first (commands.list)
better-compute commands list --tenant ID --node ID [--state STATE] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List the commands queued for a node, newest first (commands.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node (node_…) | ||
--state STATE | Only commands in this state | ||
--limit N | Page size (at most 200) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute commands list --node node_01k5w… --state failedcommands get
Show one command and its result (commands.get)
better-compute commands get COMMAND --tenant ID --node ID [--config PATH] [--url URL]Show one command and its result (commands.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node (node_…) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute commands get cmd_01k5w… --node node_01k5w…commands cancel
Cancel a command: a pending one never runs, a running one is asked to stop (commands.cancel)
better-compute commands cancel COMMAND --tenant ID --node ID [--config PATH] [--url URL]Cancel a command: a pending one never runs, a running one is asked to stop (commands.cancel)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--node ID | The node (node_…) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute commands cancel cmd_01k5w… --node node_01k5w…Catalog
sites list
List sites (sites.list)
better-compute sites list --tenant ID [--kind KIND] [--region REGION] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List sites (sites.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--kind KIND | Only this kind | ||
--region REGION | Only this region | ||
--limit N | Page size | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sites list --region eu-westsites get
Show a site (sites.get)
better-compute sites get SITE --tenant ID [--config PATH] [--url URL]Show a site (sites.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sites get site_01k5w…sites create
Create a site (sites.create)
better-compute sites create --tenant ID --kind KIND --region REGION [--iam-region REGION] [--key KEY] [--config PATH] [--url URL]Create a site (sites.create)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--kind KIND | The site kind | ||
--region REGION | Its region, e.g. eu-west | ||
--iam-region REGION | The IAM region it answers to | ||
--key KEY | Idempotency key, to retry the same request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sites create --kind dedicated --region eu-westsites update
Change a site’s region or IAM region (sites.update)
better-compute sites update SITE --tenant ID [--region REGION] [--iam-region REGION] [--clear-iam-region] [--if-version N] [--config PATH] [--url URL]Change a site’s region or IAM region (sites.update)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--region REGION | The new region | ||
--iam-region REGION | The new IAM region | ||
--clear-iam-region | Remove the IAM region | ||
--if-version N | Only if the site is still at this version | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sites update site_01k5w… --iam-region eusites delete
Delete a site (sites.delete)
better-compute sites delete SITE --tenant ID [--if-version N] [--config PATH] [--url URL]Delete a site (sites.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--if-version N | Only if the site is still at this version | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute sites delete site_01k5w…projects list
List the tenant’s projects (projects.list)
better-compute projects list --tenant ID [--state STATE] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List the tenant’s projects (projects.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--state STATE | Only this state | ||
--limit N | Page size | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute projects listprojects get
Show a project (projects.get)
better-compute projects get PROJECT --tenant ID [--config PATH] [--url URL]Show a project (projects.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute projects get prj_01k5w…projects create
Create a project (projects.create)
better-compute projects create --tenant ID --name NAME [--key KEY] [--config PATH] [--url URL]Create a project (projects.create)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--name NAME | Lowercase letters, digits and dashes | ||
--key KEY | Idempotency key, to retry the same request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute projects create --name trainingprojects archive
Archive a project (projects.archive)
better-compute projects archive PROJECT --tenant ID [--config PATH] [--url URL]Archive a project (projects.archive)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute projects archive prj_01k5w…images list
List catalog images (images.list)
better-compute images list --tenant ID [--kind KIND] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List catalog images (images.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--kind KIND | Only this kind | ||
--limit N | Page size | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute images list --kind osimages get
Show a catalog image (images.get)
better-compute images get IMAGE --tenant ID [--config PATH] [--url URL]Show a catalog image (images.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute images get img_01k5w…images register
Register an image in the catalog by digest (images.register)
better-compute images register --tenant ID --ref NAME@VERSION --source URL --disk-format FORMAT --sha256 HEX [--kind KIND] [--compression ALG] [--size BYTES] [--signature BASE64] [--signer ID] [--config PATH] [--url URL]images register records name@version (--ref), where it is fetched from (--source, https:// or oci://), its format and --sha256, and optionally a signature over its identity checked with a registered signer. Nodes verify the digest of what they fetch. Decided as compute:images:publish.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--ref NAME@VERSION | e.g. ubuntu-24.04@2026.09 | ||
--source URL | Where nodes fetch it: https:// or oci:// | ||
--disk-format FORMAT | The disk format | ||
--sha256 HEX | The image digest, 64 hex digits | ||
--kind KIND | What it boots as (default os) | ||
--compression ALG | Default none | ||
--size BYTES | Its size in bytes | ||
--signature BASE64 | A signature over its identity | ||
--signer ID | The registered signer that checks --signature | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute images register --ref ubuntu-24.04@2026.09 --source https://images.example.com/u2404.qcow2 --disk-format qcow2 --sha256 3f…images promote
Promote a catalog image (images.promote)
better-compute images promote IMAGE --tenant ID [--config PATH] [--url URL]Promote a catalog image (images.promote)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute images promote img_01k5w…flavors list
List a pool’s instance flavors (flavors.list)
better-compute flavors list --tenant ID --pool ID [--config PATH] [--url URL]List a pool’s instance flavors (flavors.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool (pool_…) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute flavors list --pool pool_01k5w…flavors create
Define an instance flavor in a pool (flavors.create)
better-compute flavors create --tenant ID --pool ID --name NAME --vcpu N --memory-gib GIB --disk-gib GIB [--gpus N] [--offer ID] [--config PATH] [--url URL]Define an instance flavor in a pool (flavors.create)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool (pool_…) | ||
--name NAME | The flavor name, e.g. g1.small | ||
--vcpu N | Virtual CPUs | ||
--memory-gib GIB | Memory in GiB | ||
--disk-gib GIB | Root disk in GiB | ||
--gpus N | GPUs passed through (default 0) | ||
--offer ID | Provider pools: the provider offer it creates | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute flavors create --pool pool_01k5w… --name g1.small --vcpu 4 --memory-gib 16 --disk-gib 80flavors update
Redefine an instance flavor; running instances keep theirs (flavors.update)
better-compute flavors update --tenant ID --pool ID --name NAME --vcpu N --memory-gib GIB --disk-gib GIB [--gpus N] [--offer ID] [--config PATH] [--url URL]Redefine an instance flavor; running instances keep theirs (flavors.update)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool (pool_…) | ||
--name NAME | The flavor name, e.g. g1.small | ||
--vcpu N | Virtual CPUs | ||
--memory-gib GIB | Memory in GiB | ||
--disk-gib GIB | Root disk in GiB | ||
--gpus N | GPUs passed through (default 0) | ||
--offer ID | Provider pools: the provider offer it creates | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute flavors update --pool pool_01k5w… --name g1.small --vcpu 4 --memory-gib 32 --disk-gib 80flavors delete
Remove an instance flavor from a pool (flavors.delete)
better-compute flavors delete --tenant ID --pool ID --name NAME [--config PATH] [--url URL]Remove an instance flavor from a pool (flavors.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool (pool_…) | ||
--name NAME | The flavor name, e.g. g1.small | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute flavors delete --pool pool_01k5w… --name g1.smallquotas get
Show the tenant’s quotas and what is used, per pool (quotas.get)
better-compute quotas get --tenant ID [--pool ID] [--config PATH] [--url URL]Show the tenant’s quotas and what is used, per pool (quotas.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | Only this pool (pool_…) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute quotas get --pool pool_01k5w…quotas set
Set one quota of the tenant in a pool (quotas.set)
better-compute quotas set --tenant ID --pool ID --resource NAME --max N [--config PATH] [--url URL]Set one quota of the tenant in a pool (quotas.set)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool (pool_…) | ||
--resource NAME | The quota resource, e.g. gpus | ||
--max N | The new limit | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute quotas set --pool pool_01k5w… --resource gpus --max 64Usage
usage list
List hourly usage windows (usage.list)
better-compute usage list --tenant ID [--project ID] [--meter METER] [--from TIME] [--to TIME] [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List hourly usage windows (usage.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--project ID | Only this project’s (prj_…) | ||
--meter METER | Only this meter (gpu.hours, …) | ||
--from TIME | Windows ending after: ISO 8601, epoch ms, or -7d | ||
--to TIME | Windows starting before | ||
--limit N | Page size | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute usage list --from -7d --meter gpu.hoursusage export
Export usage for billing as CSV or JSON lines (usage.export)
better-compute usage export --tenant ID --from TIME --to TIME [--project ID] [--meter METER] [--export-format FORMAT] [--out PATH] [--config PATH] [--url URL]usage export returns every hourly window between --from and --to (at most 93 days apart) and the total per meter. With --out the CSV (or JSON lines) goes to a new file, never over one, and the output keeps the count, the totals and whether the export was truncated (too many windows: narrow the range or the meter).
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--from TIME | ISO 8601, epoch ms, or -30d | ||
--to TIME | ISO 8601, epoch ms, -1d or +0s (now) | ||
--project ID | Only this project’s (prj_…) | ||
--meter METER | Only this meter | ||
--export-format FORMAT | Default csv | ||
--out PATH | Write the export to this new file | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute usage export --from 2026-09-01 --to 2026-10-01 --out september.csvWebhooks
webhooks list
List the tenant’s webhooks (webhooks.list)
better-compute webhooks list --tenant ID [--config PATH] [--url URL]List the tenant’s webhooks (webhooks.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute webhooks listwebhooks get
Show a webhook (webhooks.get)
better-compute webhooks get WEBHOOK --tenant ID [--config PATH] [--url URL]Show a webhook (webhooks.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute webhooks get whk_01k5w…webhooks create
Send the tenant’s events to a URL, signed (webhooks.create)
better-compute webhooks create --tenant ID --endpoint URL --events PATTERN,… [--description TEXT] [--secret-out PATH] [--config PATH] [--url URL]webhooks create posts every event matching --events (type patterns: node._, reservation.placed, _) to --endpoint, signed with X-Better-Compute-Signature. The signing secret is shown once: with --secret-out it goes to a new 0600 file instead of the output.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--endpoint URL | Where events are posted (https) | ||
--events PATTERN,… | Event type patterns | ||
--description TEXT | What it is for | ||
--secret-out PATH | Write the signing secret to this new file instead of printing it | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute webhooks create --endpoint https://hooks.example.com/compute --events "node.*,reservation.*" --secret-out ./whk.secretwebhooks update
Change a webhook’s URL, events, description, or pause it (webhooks.update)
better-compute webhooks update WEBHOOK --tenant ID [--endpoint URL] [--events PATTERN,…] [--description TEXT] [--pause] [--resume] [--config PATH] [--url URL]Change a webhook’s URL, events, description, or pause it (webhooks.update)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--endpoint URL | The new URL events are posted to | ||
--events PATTERN,… | The new event type patterns | ||
--description TEXT | The new description | ||
--pause | Stop delivering (active = false) | ||
--resume | Deliver again (active = true) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute webhooks update whk_01k5w… --pausewebhooks delete
Delete a webhook (webhooks.delete)
better-compute webhooks delete WEBHOOK --tenant ID [--config PATH] [--url URL]Delete a webhook (webhooks.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute webhooks delete whk_01k5w…webhooks ping
Send a webhook a test delivery (webhooks.ping)
better-compute webhooks ping WEBHOOK --tenant ID [--config PATH] [--url URL]Send a webhook a test delivery (webhooks.ping)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute webhooks ping whk_01k5w…webhooks rotate-secret
Replace a webhook’s signing secret (webhooks.rotateSecret)
better-compute webhooks rotate-secret WEBHOOK --tenant ID [--keep-previous DURATION] [--secret-out PATH] [--config PATH] [--url URL]webhooks rotate-secret issues a new signing secret, shown once (or written to --secret-out). --keep-previous signs with the old one too for that long (at most 24h), so the receiver can switch without dropping deliveries.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--keep-previous DURATION | Keep signing with the old secret this long | ||
--secret-out PATH | Write the signing secret to this new file instead of printing it | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute webhooks rotate-secret whk_01k5w… --keep-previous 1h --secret-out ./whk.secret.newwebhooks deliveries
List a webhook’s deliveries (webhooks.deliveries)
better-compute webhooks deliveries WEBHOOK --tenant ID [--state STATE] [--limit N] [--config PATH] [--url URL]List a webhook’s deliveries (webhooks.deliveries)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--state STATE | Only deliveries in this state | ||
--limit N | At most this many | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute webhooks deliveries whk_01k5w… --state deadwebhooks redeliver
Deliver one event again (webhooks.redeliver)
better-compute webhooks redeliver DELIVERY --tenant ID [--config PATH] [--url URL]Deliver one event again (webhooks.redeliver)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute webhooks redeliver dlv_01k5w…webhooks event-types
List the event types a webhook can subscribe to (webhooks.eventTypes)
better-compute webhooks event-types --tenant ID [--config PATH] [--url URL]List the event types a webhook can subscribe to (webhooks.eventTypes)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute webhooks event-typesPools
pools get
Show a pool: its class, policy and offers (pools.get)
better-compute pools get POOL --tenant ID [--config PATH] [--url URL]Show a pool: its class, policy and offers (pools.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pools get pool_01k5w…pools create
Create a pool in a site (pools.create)
better-compute pools create --tenant ID --site ID --class CLASS [--gpu-model MODEL] [--sharing MODE] [--policy-file PATH] [--owner-quota RES=N,…] [--provider-account ID] [--key KEY] [--config PATH] [--url URL]pools create makes a --class pool in --site, owned by the tenant. --policy-file is a PoolPolicy as JSON; --owner-quota sets the owner’s own limits (default: unlimited GPUs). Provider pools name their --provider-account and run no agent. Decided as compute:pools:create.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--site ID | The site (site_…) | ||
--class CLASS | The pool class | ||
--gpu-model MODEL | The GPU model it holds (H100, …) | ||
--sharing MODE | How GPUs are shared (default exclusive) | ||
--policy-file PATH | The PoolPolicy, as JSON | ||
--owner-quota RES=N,… | The owner’s limits, e.g. gpus=64 | ||
--provider-account ID | Provider pools: the account (pacct_…) | ||
--key KEY | Idempotency key: a retry returns the same pool | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pools create --site site_01k5w… --class metal-host --gpu-model H100 --owner-quota gpus=64pools update
Replace a pool’s policy or change its GPU model (pools.update)
better-compute pools update POOL --tenant ID [--policy-file PATH] [--gpu-model MODEL] [--config PATH] [--url URL]Replace a pool’s policy or change its GPU model (pools.update)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--policy-file PATH | The new PoolPolicy, as JSON (replaces the old one) | ||
--gpu-model MODEL | The new GPU model | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pools update pool_01k5w… --policy-file policy.jsonpools archive
Archive a pool (pools.archive)
better-compute pools archive POOL --tenant ID [--config PATH] [--url URL]Archive a pool (pools.archive)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pools archive pool_01k5w…pools offer
Offer a pool to another tenant with a quota (pools.offer)
better-compute pools offer POOL --tenant ID --to TENANT --quota RES=N,… [--include-descendants] [--priority N] [--config PATH] [--url URL]Offer a pool to another tenant with a quota (pools.offer)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--to TENANT | The tenant it is offered to | ||
--quota RES=N,… | That tenant’s limits, e.g. gpus=8 | ||
--include-descendants | Also that tenant’s child tenants | ||
--priority N | Scheduling priority | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pools offer pool_01k5w… --to org_research --quota gpus=16pools unoffer
Withdraw a pool’s offer to a tenant (pools.unoffer)
better-compute pools unoffer POOL --tenant ID --to TENANT [--config PATH] [--url URL]Withdraw a pool’s offer to a tenant (pools.unoffer)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--to TENANT | The tenant to withdraw it from | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pools unoffer pool_01k5w… --to org_researchdrivers list
List the drivers this deployment runs (drivers.list)
better-compute drivers list --tenant ID [--kind KIND] [--config PATH] [--url URL]List the drivers this deployment runs (drivers.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--kind KIND | Only this kind (runtime, bmc, …) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute drivers list --kind runtimeSecrets
secrets put
Store a secret for secret:// references (secrets.put)
better-compute secrets put --tenant ID --name NAME [--value-file PATH] [--stdin] [--scope SCOPE] [--key KEY] [--config PATH] [--url URL]secrets put stores the value of --value-file, or of standard input with --stdin, under --name; user data, sandbox environments and plugins name it as secret://<tenant>/<name>. The value never goes on the command line (shell history, the process list). --scope fleet stores a platform secret. Decided as compute:secrets:manage.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--name NAME | The secret name | ||
--value-file PATH | Read the value from this file | ||
--stdin | Read the value from standard input | ||
--scope SCOPE | Default tenant | ||
--key KEY | Idempotency key, to retry the same request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute secrets put --name hf-token --value-file ./hf-token
vault read -field=token secret/hf | better-compute secrets put --name hf-token --stdinsecrets delete
Delete a secret (secrets.delete)
better-compute secrets delete --tenant ID --name NAME [--scope SCOPE] [--config PATH] [--url URL]Delete a secret (secrets.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--name NAME | The secret name | ||
--scope SCOPE | Default tenant | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute secrets delete --name hf-tokenMetal
metal enroll
Enroll a machine by its BMC into a pool (metal.enroll)
better-compute metal enroll --tenant ID --site ID --pool ID --bmc-address HOST|URL --bmc-driver DRIVER [--bmc-credentials REF] [--bmc-username USER] [--bmc-password-file PATH] [--bmc-tls-spki HEX] [--macs MAC,…] [--product-uuid UUID] [--arch ARCH] [--legacy-bios] [--hardware-profile NAME] [--config PATH] [--url URL]metal enroll creates a node in --pool of --site from its BMC (--bmc-address, --bmc-driver) and queues BMC verification, inspection and commissioning. The BMC credentials are a reference (--bmc-credentials secret://…, vault://… or env://…), or --bmc-username with --bmc-password-file, which the server stores in its secret broker at once and never echoes. --bmc-tls-spki pins the BMC certificate. Decided as compute:nodes:provision.
| Flag | Description | Default | Environment |
| -------------------------- | ------------------------------------------------------------------------------------------------------------- | --------------- | ----------------------- | --- |
| --tenant ID | The tenant acting (the caller’s organization) | | BETTER_COMPUTE_TENANT |
| --site ID | The site the machine is in | | |
| --pool ID | The pool it joins | | |
| --bmc-address HOST | URL | The BMC address | | |
| --bmc-driver DRIVER | The BMC driver, e.g. redfish | | |
| --bmc-credentials REF | secret://, vault:// or env:// reference | | |
| --bmc-username USER | With --bmc-password-file, instead of a reference | | |
| --bmc-password-file PATH | A file holding the BMC password | | |
| --bmc-tls-spki HEX | SHA-256 of the BMC certificate’s public key | | |
| --macs MAC,… | Its MAC addresses, for PXE and matching | | |
| --product-uuid UUID | Its SMBIOS product UUID | | |
| --arch ARCH | Default x86_64 | | |
| --legacy-bios | Boots in legacy BIOS mode, not UEFI | | |
| --hardware-profile NAME | Overrides the pool’s hardware profile | | |
| --config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | | BETTER_COMPUTE_CONFIG |
| --url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | | BETTER_COMPUTE_URL |
| --format FORMAT | Output as json (indented, default), compact (one line), or table | | |
| --query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) | | |
better-compute metal enroll --site site_01k5w… --pool pool_01k5w… --bmc-address 10.20.0.14 --bmc-driver redfish --bmc-credentials secret://org_acme/bmc-r12metal manage
Re-verify a ready node’s BMC access, then re-inspect and re-commission it (metal.manage)
better-compute metal manage NODE --tenant ID [--config PATH] [--url URL]Re-verify a ready node’s BMC access, then re-inspect and re-commission it (metal.manage)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal manage node_01k5w…metal inspect
Boot a ready node into the ramdisk to report its inventory (metal.inspect)
better-compute metal inspect NODE --tenant ID [--config PATH] [--url URL]Boot a ready node into the ramdisk to report its inventory (metal.inspect)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal inspect node_01k5w…metal provide
Commission a ready node: diagnostics, a quick wipe, power off (metal.provide)
better-compute metal provide NODE --tenant ID [--config PATH] [--url URL]Commission a ready node: diagnostics, a quick wipe, power off (metal.provide)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal provide node_01k5w…metal rescue
Boot a deployed node into the rescue ramdisk (metal.rescue)
better-compute metal rescue NODE --tenant ID [--config PATH] [--url URL]Boot a deployed node into the rescue ramdisk (metal.rescue)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal rescue node_01k5w…metal unrescue
Boot a rescued node back into its installed OS (metal.unrescue)
better-compute metal unrescue NODE --tenant ID [--config PATH] [--url URL]Boot a rescued node back into its installed OS (metal.unrescue)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal unrescue node_01k5w…metal recover
Move a failed node back to the last stable point for the state it failed in (metal.recover)
better-compute metal recover NODE --tenant ID [--config PATH] [--url URL]Move a failed node back to the last stable point for the state it failed in (metal.recover)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal recover node_01k5w…metal retire
Retire a node: its retiring workflow erases its disks and powers it off (metal.retire)
better-compute metal retire NODE --tenant ID [--config PATH] [--url URL]Retire a node: its retiring workflow erases its disks and powers it off (metal.retire)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal retire node_01k5w…metal deploy
Deploy a provision profile version on a ready node (metal.deploy)
better-compute metal deploy NODE --tenant ID --profile ID --profile-version N [--config PATH] [--url URL]Deploy a provision profile version on a ready node (metal.deploy)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--profile ID | The provision profile | ||
--profile-version N | Its version | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal deploy node_01k5w… --profile ubuntu-gpu --profile-version 3metal undeploy
Release a deployed node: wipe its disks and power it off (metal.undeploy)
better-compute metal undeploy NODE --tenant ID [--wipe MODE] [--config PATH] [--url URL]Release a deployed node: wipe its disks and power it off (metal.undeploy)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--wipe MODE | How the disks are wiped (default quick) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal undeploy node_01k5w… --wipe secure-erasemetal abort
Stop a node’s running workflow and mark it failed (metal.abort)
better-compute metal abort NODE --tenant ID [--reason TEXT] [--config PATH] [--url URL]Stop a node’s running workflow and mark it failed (metal.abort)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--reason TEXT | Recorded as its last error | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal abort node_01k5w… --reason "wrong profile"metal discovered
Machines a site saw PXE-booting from unknown MACs (metal.discovered)
better-compute metal discovered --tenant ID --site ID [--config PATH] [--url URL]metal discovered lists what the site agent saw PXE/HTTP-boot from MACs with no boot entry: MAC, SMBIOS UUID, architecture, relay, first and last seen, and the enrolled machine it is a candidate for. Nothing in it is trusted or bound: confirm a candidate with metal confirm-mac.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--site ID | The site (site_…) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal discovered --site site_01k5w… --format tablemetal confirm-mac
Bind the PXE MAC of a machine enrolled without one (metal.confirmMac)
better-compute metal confirm-mac NODE --tenant ID --mac MAC [--config PATH] [--url URL]metal confirm-mac is the operator's decision that --mac is this machine's PXE MAC, usually the candidate metal discovered shows for it. Only then is the machine booted from that MAC; a MAC another machine holds is CONFLICT. The decision is audited (node.pxe-mac.confirmed).
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--mac MAC | The machine's PXE MAC (aa:bb:cc:dd:ee:ff) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal confirm-mac node_01k5w… --mac 3c:ec:ef:12:34:56metal power
Send a BMC power action through the site agent (metal.power)
better-compute metal power NODE --tenant ID --action ACTION [--config PATH] [--url URL]Send a BMC power action through the site agent (metal.power)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--action ACTION | The power action | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal power node_01k5w… --action graceful-restartmetal bulk
Run one lifecycle verb on many nodes of a pool as one batch (metal.bulk)
better-compute metal bulk --tenant ID --pool ID --verb VERB [--nodes ID,…] [--nodes-file PATH] [--wipe MODE] --reason TEXT [--config PATH] [--url URL]metal bulk runs --verb on the nodes in --nodes (comma-separated) or --nodes-file (one per line) of --pool as one batch; destructive verbs wait for the batch quorum’s approvers, who see --reason. Decided as compute:nodes:provision.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The pool every node is in | ||
--verb VERB | The verb every node gets | ||
--nodes ID,… | The nodes | ||
--nodes-file PATH | The nodes, one id per line | ||
--wipe MODE | How the disks are wiped (default quick) | ||
--reason TEXT | What the batch is for | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute metal bulk --pool pool_01k5w… --verb retire --nodes-file retire.txt --reason "EOL rack r12"profiles list
List provision profiles: the tenant’s, public ones and the modules’ (profiles.list)
better-compute profiles list --tenant ID [--limit N] [--cursor CURSOR] [--config PATH] [--url URL]List provision profiles: the tenant’s, public ones and the modules’ (profiles.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--limit N | Page size (at most 200) | ||
--cursor CURSOR | The cursor of the previous page | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute profiles listprofiles get
Show a profile version, the latest by default (profiles.get)
better-compute profiles get PROFILE --tenant ID [--profile-version N] [--config PATH] [--url URL]Show a profile version, the latest by default (profiles.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--profile-version N | The version (default: the latest) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute profiles get ubuntu-gpu --profile-version 3profiles validate
Check a profile version against the registered steps (profiles.validate)
better-compute profiles validate PROFILE --tenant ID [--profile-version N] [--config PATH] [--url URL]Check a profile version against the registered steps (profiles.validate)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--profile-version N | The version (default: the latest) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute profiles validate ubuntu-gpu --profile-version 3profiles render
Show the steps a workflow of a profile version would run (profiles.render)
better-compute profiles render PROFILE --tenant ID [--profile-version N] [--config PATH] [--url URL]Show the steps a workflow of a profile version would run (profiles.render)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--profile-version N | The version (default: the latest) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute profiles render ubuntu-gpu --profile-version 3profiles create
Store a profile version from a JSON document (profiles.create)
better-compute profiles create FILE --tenant ID [--public] [--config PATH] [--url URL]Store a profile version from a JSON document (profiles.create)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--public | Let every tenant use it (default private) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute profiles create ./ubuntu-gpu.v3.jsonprofiles update
Replace a profile version’s document or change its visibility (profiles.update)
better-compute profiles update PROFILE --tenant ID --profile-version N [--file PATH] [--visibility VIS] [--if-version N] [--config PATH] [--url URL]Replace a profile version’s document or change its visibility (profiles.update)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--profile-version N | The version to change | ||
--file PATH | A replacement document (same id and version) | ||
--visibility VIS | Who may use it | ||
--if-version N | Only if the row is still at this version | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute profiles update ubuntu-gpu --profile-version 3 --visibility publicprofiles delete
Hide a profile version, or every version, from new workflows (profiles.delete)
better-compute profiles delete PROFILE --tenant ID [--profile-version N] [--config PATH] [--url URL]Hide a profile version, or every version, from new workflows (profiles.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--profile-version N | Only this version (default: every version) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute profiles delete ubuntu-gpu --profile-version 2provider-accounts list
List the tenant’s provider accounts (providerAccounts.list)
better-compute provider-accounts list --tenant ID [--config PATH] [--url URL]List the tenant’s provider accounts (providerAccounts.list)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute provider-accounts listprovider-accounts get
Show a provider account (providerAccounts.get)
better-compute provider-accounts get ACCOUNT --tenant ID [--config PATH] [--url URL]Show a provider account (providerAccounts.get)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute provider-accounts get pacct_01k5w…provider-accounts delete
Delete a provider account no pool or instance uses (providerAccounts.delete)
better-compute provider-accounts delete ACCOUNT --tenant ID [--config PATH] [--url URL]Delete a provider account no pool or instance uses (providerAccounts.delete)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute provider-accounts delete pacct_01k5w…provider-accounts create
Store a provider account; its config is checked by the provider (providerAccounts.create)
better-compute provider-accounts create --tenant ID --provider ID --name NAME [--config-file PATH] [--key KEY] [--config PATH] [--url URL]provider-accounts create names an account of --provider and stores --config-file (JSON), checked against the provider’s manifest. Credentials in it are secret references only (secret://…), never values.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--provider ID | The provider, e.g. provider-hetzner | ||
--name NAME | The account name | ||
--config-file PATH | The account config, as JSON | ||
--key KEY | Idempotency key: a retry returns the same account | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute provider-accounts create --provider provider-hetzner --name hetzner-main --config-file hetzner.jsonprovider-accounts update
Replace a provider account’s config (providerAccounts.update)
better-compute provider-accounts update ACCOUNT --tenant ID --config-file PATH [--config PATH] [--url URL]Replace a provider account’s config (providerAccounts.update)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--config-file PATH | The new config, as JSON | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute provider-accounts update pacct_01k5w… --config-file hetzner.jsonprovider-accounts offers
Ask the provider which machine types the account can get (providerAccounts.offers)
better-compute provider-accounts offers ACCOUNT --tenant ID [--kind KIND] [--region REGION] [--gpu-model MODEL] [--config PATH] [--url URL]Ask the provider which machine types the account can get (providerAccounts.offers)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--kind KIND | Only this kind | ||
--region REGION | Only this provider region | ||
--gpu-model MODEL | Only this GPU model | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute provider-accounts offers pacct_01k5w… --kind metal --gpu-model H100provider-accounts bootstrap
Turn a provider machine into a bcd host of a pool (providerAccounts.bootstrap)
better-compute provider-accounts bootstrap ACCOUNT --tenant ID --pool ID [--machine ID] [--offer ID] [--key KEY] [--config PATH] [--url URL]Turn a provider machine into a bcd host of a pool (providerAccounts.bootstrap)
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--pool ID | The vps-host or metal-host pool it joins | ||
--machine ID | A machine the account already has | ||
--offer ID | An offer to order a machine from | ||
--key KEY | Idempotency key, to retry the same request | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute provider-accounts bootstrap pacct_01k5w… --pool pool_01k5w… --offer ax102-h100Fleet
fleet export
Write the tenant's platform objects as a FleetConfig document (fleet.export)
better-compute fleet export --tenant ID [--out PATH] [--config PATH] [--url URL]fleet export prints (or writes with --out) the sites, provider accounts, pools with their owner quotas and offers, and VPS flavors the tenant owns, keyed by name. Objects fleet did not create are named by their id; rename them in the document and the next apply keeps them. Secrets appear only as references.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--out PATH | Write the document to a new file | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute fleet export --out fleet.jsonfleet plan
Show what applying a FleetConfig document would change (fleet.plan)
better-compute fleet plan FILE --tenant ID [--prune] [--fail-on-drift] [--calls] [--config PATH] [--url URL]fleet plan diffs the document against the tenant's current objects and prints each change: + create, ~ update (with the fields), - delete (only with --prune), and BLOCKED for changes the platform cannot make (a site's region, a pool's class or site, dangling names). It changes nothing. The printed planHash, passed to fleet apply --plan-hash, applies exactly this plan. With --fail-on-drift it exits FLEET_DRIFTED when anything would change, for drift checks in CI; a blocked plan always exits PLAN_BLOCKED.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--prune | Also delete what the document no longer lists (pools are archived) | ||
--fail-on-drift | Exit FLEET_DRIFTED when the plan is not empty | ||
--calls | Also print the API calls apply would make | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute fleet plan fleet.json
better-compute fleet plan fleet.json --prune --fail-on-driftfleet status
Show the last applied document and whether the fleet drifted from it (fleet.status)
better-compute fleet status --tenant ID [--fail-on-drift] [--config PATH] [--url URL]fleet status shows the planHash, author and time of the tenant's last fleet apply, and the drift the fleet.drift job found when it last re-planned that document (every 15 minutes by default): changes made outside fleet, listed like fleet plan. With --fail-on-drift it exits FLEET_DRIFTED while there is drift, for monitoring.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--fail-on-drift | Exit FLEET_DRIFTED while the fleet drifted | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute fleet status
better-compute fleet status --fail-on-driftfleet apply
Apply a FleetConfig document (fleet.plan, then fleet.apply)
better-compute fleet apply FILE --tenant ID [--prune] [--plan-hash HASH] [--yes] [--config PATH] [--url URL]fleet apply plans the document, prints the changes, then applies exactly that plan. Every underlying call (sites.create, pools., quotas.set, flavors., providerAccounts.*) is decided for you before anything runs, and then all of them run in one transaction, so a denial or failure applies nothing. If the fleet changes between the plan and the apply, nothing is applied and the command exits CONFIG_DRIFT. Pass --plan-hash to apply a plan reviewed earlier with fleet plan; without --yes it only plans.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--prune | Also delete what the document no longer lists (pools are archived) | ||
--plan-hash HASH | Apply only if the plan still has this hash (from fleet plan) | ||
--yes | Apply without stopping after the plan | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute fleet apply fleet.json --yes
better-compute fleet apply fleet.json --prune --plan-hash 3f1c…daemon install-script
Write the POSIX sh script that installs bcd on a server and joins it to a pool
better-compute daemon install-script --pool ID --site ID --gateway-url URL --base-url URL [--base-path PATH] --bcd-version VERSION [--sha256 ARCH=HEX,…] [--release-manifest PATH] [--release-pins PINS] [--release-threshold N] [--plugins] [--install-plugins NAMES] [--unprivileged] [--attestor tpm] [--websocket-url URL] [--websocket-audience HOST] [--proxy-ca-file PATH] [--bmc-networks CIDRS] [--approver-set-sha256 HEX] [--instance-bridges BRIDGES] [--command-root-sha256 HEX,…] [--privileged-plugins NAMES] [--release-sequence N] [--pki PATH] [--out PATH]daemon install-script emits the bcd installer (PLAN.md §3.3, §6). The script reads the join token only from BCD_JOIN_TOKEN or standard input, downloads the pinned bcd for the machine's architecture from {base-url}{base-path}/downloads/bcd/{version}/linux-{arch}, checks it against --sha256 (or the digests of a --release-manifest verified here under --release-pins, product bcd, version --bcd-version), installs /usr/local/bin/bcd, /etc/bcd/config.toml (mode 0600: gateway URL, site and the serving CA, join signing and join encryption key pins, in bcd's sha256/<base64> form), the JoinService encryption key, and a hardened bcd.service, then runs bcd join and starts the service. Run on a configured host without a token, it upgrades bcd in place. The pins come from the PKI bundle's public half (pki init), so no secret is needed. The script holds no secret either: create the join token separately (joinTokens.create) and hand it over out of band. --plugins prepares the node for bcx driver plugins: a [plugins] section (dir /usr/local/lib/bcd/plugins, a child of bcd's delegated cgroup) and a bcd.service.d drop-in that lets bcd run each plugin under its own uid in its own cgroup (CAP_SETUID/CAP_SETGID/CAP_KILL, Delegate=yes); --privileged-plugins names the ones that run as root and make namespaces (Kata). --install-plugins bcx-ipmi also installs plugins a release ships: each archive from {base-url}{base-path}/downloads/{name}/{version}/linux-{arch} is checked against its digest in the verified --release-manifest, only the plugin's own regular file is taken from it, and its binary digest becomes its line in the plugins' pins file. Any node whose config.toml has a [plugins] section gets the drop-in, and an upgrade keeps the sections the operator configured.
| Flag | Description | Default | Environment |
|---|---|---|---|
--pool ID | The pool the node joins (named in the script) | ||
--site ID | The pool's site id (config.toml site) | ||
--gateway-url URL | The regional gateway bcd dials, https://… | BETTER_COMPUTE_GATEWAY_URL | |
--base-url URL | The control plane serving the bcd downloads, https://… | BETTER_COMPUTE_BASE_URL | |
--base-path PATH | The API's base path | /api/compute | |
--bcd-version VERSION | The bcd release to install, e.g. 0.1.0 | BETTER_COMPUTE_BCD_VERSION | |
--sha256 ARCH=HEX,… | SHA-256 of each architecture’s binary: amd64=<hex>,arm64=<hex> (or use --release-manifest) | ||
--release-manifest PATH | A signed bcd release manifest: its verified digests are pinned instead | ||
--release-pins PINS | Comma-separated sha256/… pins of the release keys | BCD_RELEASE_PINS | |
--release-threshold N | Release keys that must have signed (default 1) | ||
--plugins | Prepare the node for bcx driver plugins ([plugins], the systemd drop-in) | ||
--install-plugins NAMES | Install these bcx plugins from the release, pinned by --release-manifest (bcx-ipmi; implies --plugins) | ||
--unprivileged | Run bcd node as the unprivileged bcd user beside a root bcd helper (privilege separation) | ||
--attestor tpm | Join with the host's TPM (the tpm attestor: its endorsement key is the credential; the attestor's policy decides the pool) instead of a join token | ||
--websocket-url URL | Dial the gateway over WebSocket (wss://…/v1/session) behind TLS-inspecting proxies | ||
--websocket-audience HOST | The gateway's public host the WebSocket proof names (default: the URL's host) | ||
--proxy-ca-file PATH | The TLS-inspecting proxy's CA (PEM), trusted for the WebSocket's TLS only | ||
--bmc-networks CIDRS | A site agent's BMC networks (comma-separated): site.httpProxy never reaches into them | ||
--approver-set-sha256 HEX | Pin the deployment's approver set (pki trust-version prints it): its first set, or nothing destructive | ||
--instance-bridges BRIDGES | With --unprivileged, on VPS and sandbox hosts: the bridges instance NICs may join ([helper] instance_bridges, comma-separated) | ||
--command-root-sha256 HEX,… | Pin the command-signing roots (pki trust-version prints them): bcd helper applies host config units only from specs signed under them. Default: the PKI bundle’s current and next roots | ||
--privileged-plugins NAMES | Plugins that run as root without the seccomp filter (comma-separated; implies --plugins) | ||
--release-sequence N | bcd's release floor ([update] release_sequence): it never installs an older release | ||
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--out PATH | Write the script to a new file (mode 0755) instead of standard output |
better-compute daemon install-script --pool pool_h100 --site fsn1 --gateway-url https://gw.eu.example.com --base-url https://compute.example.com --bcd-version 0.1.0 --sha256 amd64=<hex> > install-bcd.sh
BCD_JOIN_TOKEN=bcjt_... sudo -E sh install-bcd.shPKI
pki init
Create the machine PKI: root, node, serving and internal CAs and the JoinService keys
better-compute pki init --trust-domain DOMAIN [--pki PATH] [--offline-root PATH] [--organization NAME] [--plaintext]pki init creates a deployment's machine PKI (PLAN.md §13) and writes it to one JSON file with mode 0600: an offline root CA, the per-region node CA (agent client certificates), the gateway serving CA, the internal control-plane CA, and the JoinService signing and encryption keys. No key does two jobs. The private keys are sealed with AES-256-GCM under a key derived from BETTER_COMPUTE_SECRET; without the secret, pass --plaintext to store them as PEM instead. --offline-root writes the root key to its own file and leaves it out of the bundle: keep that file off the servers. It prints the pins install scripts need (the same as pki show) and never overwrites an existing file.
| Flag | Description | Default | Environment |
|---|---|---|---|
--trust-domain DOMAIN | SPIFFE trust domain of agent identities, e.g. compute.example.com | BETTER_COMPUTE_TRUST_DOMAIN | |
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--offline-root PATH | Write the root key here (sealed like the bundle) and leave it out of the bundle | ||
--organization NAME | Subject organization of the CA certificates | better-compute | |
--plaintext | Store private keys as PEM (mode 0600) when BETTER_COMPUTE_SECRET is not set | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
BETTER_COMPUTE_SECRET=... better-compute pki init --trust-domain compute.example.com
better-compute pki init --trust-domain compute.test --plaintext --pki ./dev/pki.json
better-compute pki init --trust-domain compute.example.com --offline-root /media/usb/root-ca.keypki show
Print the pins install scripts and bcd need, and the CA expiry dates
better-compute pki show [--pki PATH]pki show prints the trust domain, the gateway serving CA's SPKI pin, the JoinService signing and encryption key pins in bcd's sha256/<base64> form, the encryption key as a JWK, and when each CA expires. With BETTER_COMPUTE_SECRET the public half is checked against the seal first (authenticated: true); without it the pins come from a file nothing vouches for, and a warning says so.
| Flag | Description | Default | Environment |
|---|---|---|---|
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pki show
better-compute pki show --query servingCaSpkiPinpki add-sandbox-ca
Add the sandbox SSH CA to a bundle made before sandboxes
better-compute pki add-sandbox-ca [--pki PATH]pki add-sandbox-ca creates the sandbox SSH CA (PLAN.md §3.7) in a bundle that lacks it and writes the bundle back (sealed with BETTER_COMPUTE_SECRET when set). sandboxes.exec signs with it (the tunnels module's sandboxSsh, pki tunnelsOptions()) and sandbox guests trust its public key (vps({ sandboxExec: { caPublicKey } })); it is separate from the break-glass CA, so a sandbox certificate never opens a node. Bundles from pki init already have one.
| Flag | Description | Default | Environment |
|---|---|---|---|
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pki add-sandbox-capki reseal
Seal the bundle in the current format, authenticating its public parts
better-compute pki reseal [--pki PATH] [--accept-unauthenticated]pki reseal rewrites the bundle sealed with BETTER_COMPUTE_SECRET in the current format, where the seal also covers every certificate and pin, so a file changed without the secret no longer loads. Bundles sealed before that format, or left unsealed while a secret is set, are refused everywhere else. First compare the pins it prints (the same as pki show) with the ones your install scripts and join tokens use, and check certificates (the SHA-256 of every certificate in every chain) holds nothing you did not put there: it seals whatever the file holds now. Needs BETTER_COMPUTE_SECRET; the current key and certificates are kept, nothing is rotated.
| Flag | Description | Default | Environment |
|---|---|---|---|
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--accept-unauthenticated | Seal a bundle nothing authenticates, after comparing the pins printed without it | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pki reseal
better-compute pki reseal --accept-unauthenticatedpki rotate-command-root
Rotate the command-signing root in three steps: add, switch, drop
better-compute pki rotate-command-root --stage STAGE [--pki PATH] [--force]pki rotate-command-root performs one step of a command-signing root rotation (PLAN.md §13) on the bundle and writes it back (sealed with BETTER_COMPUTE_SECRET when set). --stage add creates a new root and publishes it beside the current one (the trust bundle's version goes up); workers keep signing under the current root. Roll the bundle out to every process: daemons receive the new version in Welcome.trust. --stage switch, once every daemon holds that version, makes workers sign under the new root while the old one stays trusted. --stage drop, at least 24 hours later (worker keys live at most 24 h), removes the old root (version up again). Each step prints the roots and version daemons will trust.
| Flag | Description | Default | Environment |
|---|---|---|---|
--stage STAGE | add a new root, switch signing to it, or drop the old one | ||
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--force | switch without checking that every connected daemon has the new trust version | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pki rotate-command-root --stage add
better-compute pki rotate-command-root --stage switch
better-compute pki rotate-command-root --stage droppki trust-version
Show the trust bundle version the deployment publishes, and the one to sign a quorum change for
better-compute pki trust-version [--pki PATH] [--config PATH]pki trust-version reads the trust bundle the deployment last published (its version follows its content: a changed bundle publishes the next version, pki.trustVersion is a floor) and compares it with this configuration and PKI bundle: whether they publish the same bundle, the published approver-set epoch, whether the configured approver quorum differs (then its current approvers sign it for signQuorumForEpoch: better-compute batch sign-approvers --epoch <n>, with pki.approvers.epoch set to it), and how many connected daemons hold that version.
| Flag | Description | Default | Environment |
|---|---|---|---|
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pki trust-versionpki renew-ca
Renew a CA's certificate under the root, keeping its key
better-compute pki renew-ca --ca CA [--root-key PATH] [--days N] [--pki PATH]pki renew-ca issues a new certificate for the node, serving or internal CA from the root CA, for the same key and subject, and writes the bundle back (sealed with BETTER_COMPUTE_SECRET when set). Certificates the CA issued stay valid and the serving CA's SPKI pin does not change, so nothing is re-pinned and no node rejoins; roll the bundle out to every process before the old certificate expires (doctor warns 30 days ahead). The root key comes from the bundle or, for an offline root, from --root-key; it is never written into the bundle then.
| Flag | Description | Default | Environment |
|---|---|---|---|
--ca CA | Which CA to renew | ||
--root-key PATH | The offline root key (pki init --offline-root), when the bundle has none | ||
--days N | Lifetime of the new certificate in days (capped by the root) | 365 | |
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pki renew-ca --ca node
better-compute pki renew-ca --ca serving --root-key /media/usb/root-ca.keypki issue-gateway
Issue a gateway serving certificate and key from the serving CA
better-compute pki issue-gateway --san NAMES [--out DIR] [--name NAME] [--days N] [--pki PATH]pki issue-gateway generates a P-256 key and issues a serving certificate for it from the bundle's gateway serving CA (PLAN.md §7.1): DNS SANs from --san (comma-separated), serverAuth, 30 days by default. It writes <name>.key (mode 0600) and <name>.crt (the certificate followed by the serving CA's chain) into --out, replacing earlier files atomically so a running gateway can hot-reload them. Daemons trust the certificate through the serving CA pin (pki show).
| Flag | Description | Default | Environment |
|---|---|---|---|
--san NAMES | DNS names, comma-separated, e.g. gw.eu-central.example.com | ||
--out DIR | Directory for the key and certificate | .better-compute/gateway | |
--name NAME | File name stem: NAME.key and NAME.crt | gateway | |
--days N | Certificate lifetime in days | 30 | |
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute pki issue-gateway --san gw.eu-central.example.com
better-compute pki issue-gateway --san gw1.example.com,gw.example.com --out /etc/better-compute/tls --days 14Quorum
batch keygen
Create an approver key pair for destructive batches
better-compute batch keygen --out PATHbatch keygen creates an ECDSA P-256 approver key (PLAN.md §13): the private key (PKCS#8 PEM, mode 0600) at --out, the public key beside it at <out>.pub. Keep the private key with its operator, off the control plane (a hardware token or an offline machine is better). Add the public key to the deployment's pki.approvers.keys, e.g. approverKeyOf(readFileSync('alice.pem.pub', 'utf8')).spkiDer from @better-compute/pki, with pki.approvers.threshold; daemons receive it in their trust bundle. The kid printed is how approvals name the key. With BETTER_COMPUTE_APPROVER_PASSPHRASE set, the private key is encrypted under it (and every batch command reads it with it).
| Flag | Description | Default | Environment |
|---|---|---|---|
--out PATH | Where to write the private key (never overwritten) | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute batch keygen --out ~/.better-compute/approver.pembatch sign
Sign a batch approval offline, from its scope
better-compute batch sign --key PATH [--batch ID] [--scope PATH] [--root HEX] [--size N] [--not-after TIME] [--trust-domain DOMAIN] [--pki PATH] [--expect PATH] [--allow-unbound] [--allow-opaque] [--operations-out PATH] [--max-hours N] [--unchecked]batch sign signs one approval of a destructive batch with an approver key (--key, from batch keygen) without contacting the server: for approvers on an offline machine. Pass the batch's scope (--scope, the JSON batch show prints, or an array of { subject, kind }): the root is recomputed from it and every subject is shown by kind before signing (--expect checks them against your own list). --root and --size, when given as well, must match what the scope gives; signing --root and --size alone, a root the CLI cannot check, needs --unchecked. --not-after is the batch's expiry as the server set it (all approvers sign the same one), at most --max-hours away. Prints the signature ({ kid, sig }) to hand to batch approve --signature.
| Flag | Description | Default | Environment |
|---|---|---|---|
--key PATH | The approver private key (PEM) | ||
--batch ID | The batch id (default: the scope file's batchId) | ||
--scope PATH | The batch scope (JSON), to recompute the root from | ||
--root HEX | The scope root (64 hex digits), checked against --scope | ||
--size N | The scope size, checked against --scope | ||
--not-after TIME | The batch's expiry: ISO-8601 or epoch milliseconds (default: the scope file's notAfter) | ||
--trust-domain DOMAIN | The deployment you approve for (default: the PKI bundle's trust domain); any other is refused | BETTER_COMPUTE_TRUST_DOMAIN | |
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--expect PATH | Approve only if the batch holds exactly these subjects (one per line) or { subject, kind } commands | ||
--allow-unbound | Approve commands whose payload the batch does not fix (shown as "any payload") | ||
--allow-opaque | Approve commands whose operation the batch shows only as a digest | ||
--operations-out PATH | Also write every distinct operation in full (JSON), with the subjects that run it | ||
--max-hours N | Refuse a batch that stays open longer than this many hours | 72 | |
--unchecked | Sign --root and --size without a scope to check them against | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute batch sign --key approver.pem --scope batch.json --not-after 2026-09-25T18:00:00Z
better-compute batch sign --key approver.pem --scope batch.json --expect my-nodes.txtbatch sign-approvers
Sign a change of the approver set with a current approver key
better-compute batch sign-approvers --key PATH --epoch N [--approvers PATHS] [--threshold K] [--tiers SIZE:K,…] [--unbatched N] [--trust-domain DOMAIN] [--pki PATH]batch sign-approvers signs, as one of the CURRENT approvers (--key), the quorum a new trust bundle will carry: its approver keys (--approvers, the .pub files of the whole new set), --threshold, --tiers and --unbatched, for approver-set --epoch (one above the current set's; better-compute pki trust-version prints it) in the deployment's --trust-domain (default: the PKI bundle's; a set signed for staging never changes prod's quorum, even with shared approver keys). Daemons that hold approver keys take a changed quorum, removal included, only with such signatures from their current threshold of current approvers (PLAN.md §13): the join key alone, which the control plane holds, cannot lift or replace it. Members of the NEW set sign it too (their signatures move daemons that already hold that set to the new epoch); give all the signatures to the deployment's pki.approvers.setSignatures with pki.approvers.epoch; they stay valid on every later trust bundle version while the set is current. Prints the set's digest and the signature.
| Flag | Description | Default | Environment |
|---|---|---|---|
--key PATH | Your CURRENT approver private key (PEM) | ||
--epoch N | The new set's epoch: one above the current set's | ||
--approvers PATHS | The new set: approver public keys (.pub files, comma-separated); empty lifts the quorum | ||
--threshold K | Approvals a batch needs in the new set | ||
--tiers SIZE:K,… | Per-size thresholds, ascending, e.g. 5:1,100:2 | ||
--unbatched N | Unbatched destructive commands per hour | 0 | |
--trust-domain DOMAIN | The deployment you approve for (default: the PKI bundle's trust domain); any other is refused | BETTER_COMPUTE_TRUST_DOMAIN | |
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute batch sign-approvers --key alice.pem --epoch 2 --approvers alice.pem.pub,bob.pem.pub,carol.pem.pub --threshold 2batch list
List destructive batches, newest first
better-compute batch list --tenant ID [--state STATE] [--limit N] [--cursor ID] [--config PATH] [--url URL]batch list pages commandBatches.list: each batch with its reason, state (pending, approved, expired, cancelled), scope size, the approvals it has and needs, and its member commands by state. Needs compute:batches:read.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--state STATE | Only batches in this state | ||
--limit N | Batches per page | 50 | |
--cursor ID | The previous page's next | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute batch list --tenant org_acme --state pendingbatch show
Show a batch and check its scope against its root
better-compute batch show --tenant ID --batch ID [--scope-out PATH] [--config PATH] [--url URL]batch show reads a batch (commandBatches.get), pages its scope (commandBatches.scope) and recomputes the Merkle root from the listed (subject, kind) commands: it fails with SCOPE_MISMATCH when they do not give the root the server asks approvers to sign. --scope-out writes the verified scope with the batch's expiry, the input of batch sign on an offline machine.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--batch ID | The batch (batch_…) | ||
--scope-out PATH | Write the verified scope (JSON) for batch sign | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute batch show --tenant org_acme --batch batch_01k5w…
better-compute batch show --tenant org_acme --batch batch_01k5w… --scope-out batch.jsonbatch approve
Approve a destructive batch with your approver key
better-compute batch approve --tenant ID --batch ID [--key PATH] [--signature PATH] [--root HEX] [--expect PATH] [--allow-unbound] [--allow-opaque] [--operations-out PATH] [--max-hours N] [--trust-domain DOMAIN] [--pki PATH] [--yes] [--config PATH] [--url URL]batch approve reads the batch, pages its scope and recomputes the root from the listed commands (refusing with SCOPE_MISMATCH when they do not give it), shows the reason, every subject by kind (--expect checks them against your own list) and the approvals so far, and then signs the batch's root, size and expiry with --key and submits the signature (commandBatches.approve, compute:batches:approve). Without --yes it stops after showing the batch; --root approves only the root you reviewed. Once the batch holds the required approvals it is released and its commands run. With --signature, submits a signature made offline by batch sign instead, after checking it is for this batch.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--batch ID | The batch (batch_…) | ||
--key PATH | Your approver private key (from batch keygen) | ||
--signature PATH | A signature from batch sign (instead of --key) | ||
--root HEX | Approve only if the batch still has this root (64 hex digits) | ||
--expect PATH | Approve only if the batch holds exactly these subjects (one per line) or { subject, kind } commands | ||
--allow-unbound | Approve commands whose payload the batch does not fix (shown as "any payload") | ||
--allow-opaque | Approve commands whose operation the batch shows only as a digest | ||
--operations-out PATH | Also write every distinct operation in full (JSON), with the subjects that run it | ||
--max-hours N | Refuse a batch that stays open longer than this many hours | 72 | |
--trust-domain DOMAIN | The deployment you approve for (default: the PKI bundle's trust domain); any other is refused | BETTER_COMPUTE_TRUST_DOMAIN | |
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--yes | Sign and submit without stopping after the summary | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute batch approve --tenant org_acme --batch batch_01k5w… --key ~/.better-compute/approver.pem
better-compute batch approve --tenant org_acme --batch batch_01k5w… --key approver.pem --root 3f1c…
better-compute batch approve --tenant org_acme --batch batch_01k5w… --signature alice.sig.jsonbatch create
Create a destructive batch that waits for its approvers
better-compute batch create --tenant ID --reason TEXT --scope PATH [--hours N] [--key KEY] [--config PATH] [--url URL]batch create creates a batch (commandBatches.create, compute:batches:create) from --scope FILE: a JSON array of { subject, kind, payload } leaves. subject is the node id for kinds a node runs on itself, bmc:<site agent node id>/<address> for bmc.*, node:<target> for site.httpProxy. payload binds the leaf to exactly one operation, which approvers are shown: { json } (the kind's payload message as proto3 JSON, encoded here) or { typeUrl, value } (base64); a leaf without one admits any payload of its kind and approvers must accept that explicitly. The batch admits its commands for --hours (default 24, at most 72) once approved; run them with commands.run { batchId }. Prints the batch; approvers then run better-compute batch approve.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--reason TEXT | What the batch does, shown to approvers | ||
--scope PATH | The leaves (JSON array of { subject, kind, payload }) | ||
--hours N | How long it admits its commands | 24 | |
--key KEY | Idempotency key: repeat it to retry the same creation | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute batch create --tenant org_acme --reason "reimage rack 7" --scope rack7.jsonbatch members
List a batch's commands: node, kind, state, whether held for approval
better-compute batch members --tenant ID --batch ID [--state STATE] [--limit N] [--cursor ID] [--config PATH] [--url URL]batch members pages commandBatches.members: every command enqueued into the batch with its node (the site agent for bmc: subjects), subject, kind and state; held ones are awaitingApproval until the batch is approved. Needs compute:batches:read.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--batch ID | The batch (batch_…) | ||
--state STATE | Only commands in this state (pending, succeeded, …) | ||
--limit N | Commands per page | 100 | |
--cursor ID | The previous page's next | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute batch members --tenant org_acme --batch batch_01k5w… --state pendingbatch cancel
Cancel a pending batch and its held commands
better-compute batch cancel --tenant ID --batch ID [--config PATH] [--url URL]batch cancel ends a pending batch (commandBatches.cancel, compute:batches:approve): none of its commands run, and the pending ones are cancelled with reason batch-cancelled.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant acting (the caller’s organization) | BETTER_COMPUTE_TENANT | |
--batch ID | The batch (batch_…) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--url URL | Call a running compute server (https://host or https://host/api/compute) instead of loading the configuration | BETTER_COMPUTE_URL | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute batch cancel --tenant org_acme --batch batch_01k5w…IAM
iam setup
Print the example compute policies and create the root billing meters in better-iam
better-compute iam setup --audience URL [--gpu-model MODEL] [--regions LIST] [--max-gpus N] [--max-hours N] [--feature FLAG] [--meters] [--iam-url URL] [--iam-base-path PATH] [--root-tenant ID] [--gpu-models LIST]iam setup prints the PLAN.md §12.6 example policies, gpu-user and agent-guardrails, for an organization administrator to apply: compute cannot write organization policies. The policies are parameterized by the session JWT audience (the compute API's URL), the GPU model, regions and limits of the bounded-reservation statement. With --meters it also creates the §12.7 root meters in better-iam: one gpu.<model>.hours per GPU model family, plus node.metal.hours, vps.vcpu.hours and vps.memory.gib.hours. Meters that already exist are left alone, so re-running is safe. Creating meters calls better-iam at --iam-url as BETTER_IAM_TOKEN, which must be a root credential, through the optional peer @better-iam/client. It sets no prices: pricing is an operator decision (billing.setPrice).
| Flag | Description | Default | Environment |
|---|---|---|---|
--audience URL | The compute API URL, used as the session JWT audience | BETTER_COMPUTE_BASE_URL | |
--gpu-model MODEL | GPU model family the bounded-reservation statement allows | H100 | |
--regions LIST | Regions the bounded-reservation statement allows, comma-separated | ||
--max-gpus N | GPUs per reservation | 8 | |
--max-hours N | Hours per reservation, extensions included | 72 | |
--feature FLAG | Tenant feature the reservation statement requires (default compute.<model>) | ||
--meters | Also create the root billing meters in better-iam | ||
--iam-url URL | better-iam base URL for --meters | BETTER_IAM_URL | |
--iam-base-path PATH | better-iam's API base path | /api/iam | |
--root-tenant ID | The root tenant that owns the meters (required with --meters) | BETTER_COMPUTE_ROOT_TENANT | |
--gpu-models LIST | GPU model families to meter, comma-separated (default: every known family) | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute iam setup --audience https://compute.example.com --query "[0]"
BETTER_IAM_TOKEN=... better-compute iam setup --audience https://compute.example.com --meters --iam-url https://iam.example.com --root-tenant ten_rootAudit
audit checkpoint
Seal committed audit events into signed per-tenant checkpoints
better-compute audit checkpoint [--pki PATH] [--limit N] [--config PATH]audit checkpoint runs what the audit module's hourly job does: it seals every audit event committed since the last checkpoint into a signed, hash-chained Merkle checkpoint per tenant, signed with the PKI bundle's audit key (unsealed with BETTER_COMPUTE_SECRET). It repeats until nothing is left. The deployment must include auditModule() and be migrated.
| Flag | Description | Default | Environment |
|---|---|---|---|
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--limit N | Events per pass (default 50000) | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute audit checkpointaudit verify
Verify a tenant's audit trail against its signed checkpoints
better-compute audit verify --tenant ID [--pin PIN] [--pki PATH] [--config PATH]audit verify recomputes every checkpoint of --tenant from the audit events as they are now: signatures under the audit key's pin, the hash chain, contiguous ranges, sizes and Merkle roots. An edited, deleted or inserted event in a sealed range, a broken chain or a foreign signature is a problem; with any problem the command exits AUDIT_TAMPERED after printing the report. It only reads.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant | BETTER_COMPUTE_TENANT | |
--pin PIN | The audit signing key pin (sha256/…); default: from the PKI bundle | BETTER_COMPUTE_AUDIT_PIN | |
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute audit verify --tenant org_acme
better-compute audit verify --tenant org_acme --query problemsaudit prove
Write an inclusion proof that one audit event is sealed
better-compute audit prove EVENT --tenant ID [--out PATH] [--config PATH]audit prove writes a self-contained proof that the event is in a signed checkpoint: the event, its Merkle path and the signed checkpoint. Anyone holding the audit key pin checks it offline with audit check-proof, without database access.
| Flag | Description | Default | Environment |
|---|---|---|---|
--tenant ID | The tenant | BETTER_COMPUTE_TENANT | |
--out PATH | Write the proof to a file instead of printing it | ||
--config PATH | Configuration module; default: the nearest better-compute.config.{mjs,js,ts,mts} | BETTER_COMPUTE_CONFIG | |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute audit prove aud_01k… --tenant org_acme --out proof.jsonaudit check-proof
Check an inclusion proof offline against the audit key pin
better-compute audit check-proof FILE [--pin PIN] [--pki PATH]audit check-proof verifies a proof written by audit prove: the checkpoint's signature under the pin and the event's Merkle path to the signed root. It needs no database; it exits INVALID_PROOF when the proof does not hold.
| Flag | Description | Default | Environment |
|---|---|---|---|
--pin PIN | The audit signing key pin (sha256/…); default: from the PKI bundle | BETTER_COMPUTE_AUDIT_PIN | |
--pki PATH | The PKI bundle written by pki init | .better-compute/pki.json | BETTER_COMPUTE_PKI |
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute audit check-proof proof.json --pin sha256/…Release
release keygen
Create an offline release signing key and print its pin
better-compute release keygen --out PATHrelease keygen writes a new P-256 release signing key to --out (owner-only, never overwritten) and its public half to <out>.pub.pem, and prints the key's pin. Keep the key offline. Give the pin to installers (BCD_RELEASE_PINS) and daemons; give the .pub.pem to whoever builds manifests that you will cosign.
| Flag | Description | Default | Environment |
|---|---|---|---|
--out PATH | Where to write the key | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute release keygen --out ~/keys/release-alice.pemrelease sign
Sign a release manifest over a directory's artifacts
better-compute release sign DIR --product NAME --version SEMVER --sequence N --key PATH [--cosigners PATHS] [--validity-days DAYS] [--out PATH]release sign hashes every file in DIR (not subdirectories; *.sha256, manifest.json and signature files are skipped), derives each artifact's platform from goreleaser names (_linux_amd64.), and writes a manifest signed with --key. --sequence must increase with every release of --product: installers and bcd refuse a manifest whose sequence is below the last one they accepted. List the public halves of keys that will cosign later with --cosigners so their signatures count.
| Flag | Description | Default | Environment |
|---|---|---|---|
--product NAME | e.g. bcd | ||
--version SEMVER | e.g. 1.4.0 | ||
--sequence N | The rollback counter: higher than every earlier release | ||
--key PATH | The signing key | ||
--cosigners PATHS | Comma-separated .pub.pem files of keys that will cosign | ||
--validity-days DAYS | How long installers accept the manifest (default 365) | ||
--out PATH | Where to write the manifest (default DIR/manifest.json) | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute release sign dist --product bcd --version 1.4.0 --sequence 14 --key ~/keys/release-alice.pemrelease cosign
Add your signature to a release manifest
better-compute release cosign MANIFEST --key PATHrelease cosign adds --key's signature to MANIFEST in place. The key must be one the manifest lists (release sign --cosigners), so a threshold of release managers can each sign on their own machine.
| Flag | Description | Default | Environment |
|---|---|---|---|
--key PATH | Your signing key | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute release cosign dist/manifest.json --key ~/keys/release-bob.pemrelease verify
Verify a release manifest (and its artifacts) against pinned keys
better-compute release verify MANIFEST --pins PINS [--threshold N] [--min-sequence N] [--product NAME] [--dir DIR]release verify checks MANIFEST the way installers and bcd do, in this order: a --threshold of distinct keys among --pins signed it; its sequence is not below --min-sequence (rollback); it has not expired; and, with --dir, every listed artifact present there matches its size and SHA-256. It exits RELEASE_REJECTED with the reason otherwise.
| Flag | Description | Default | Environment |
|---|---|---|---|
--pins PINS | Comma-separated sha256/… pins of the release keys | BCD_RELEASE_PINS | |
--threshold N | Default 1 | ||
--min-sequence N | The last sequence accepted before | ||
--product NAME | Refuse other products | ||
--dir DIR | Also check the artifacts in DIR | ||
--format FORMAT | Output as json (indented, default), compact (one line), or table | ||
--query PATH | Print only part of the result, e.g. protocol.max or findings[].check (strings print raw) |
better-compute release verify dist/manifest.json --pins sha256/…,sha256/… --threshold 2 --dir distEnvironment
| Variable | Description |
|---|---|
BETTER_COMPUTE_CONFIG | Configuration module, like --config |
BETTER_COMPUTE_TOKEN | IAM session token, API key or session JWT that token commands act as |
BETTER_COMPUTE_URL | Compute server token commands call, like --url |
BETTER_COMPUTE_DATABASE_URL | Without a configuration file: the database (postgres://, pglite:DIR, pglite:memory), with BETTER_COMPUTE_SECRET |
BETTER_COMPUTE_SECRET | Without a configuration file: the deployment secret (at least 32 characters) |
BETTER_COMPUTE_BASE_URL | Without a configuration file: the public origin (default http://localhost:3000) |
BETTER_COMPUTE_DEBUG | Print the stack trace of a failure |
Better Compute is created by Sean Filimon
Last updated
workflows
The workflows group reads the provisioning workflows of a node and lets an operator abort, retry, pause or resume one. Workflows are started by other modules, such as metal for each workflow-driven provision state, not through this group. Every method is decided on the node (`compute-node`): reads as `compute:workflows:read`, the others as `compute:workflows:manage`. See [Provisioning workflows](/docs/guides/bare-metal/workflows).
Protocol
Every service, message and enum of the daemon protocol, from the .proto sources, with field numbers and types.