BoxLite CLI
Command-line interface for BoxLite — use BoxLite without writing code, with a familiar Docker/Podman-like experience.
For CLI development (build, test, adding commands), see CLI Development Guide.
Platforms: macOS (Apple Silicon), Linux (x86_64, ARM64)
Overview
The BoxLite CLI (boxlite) lets you create, run, and manage BoxLite boxes from the terminal. It targets quick testing, shell scripting and automation, debugging, and demos.
Key Features
- Run — Create a box from an image or prepared rootfs and run a command (interactive, TTY, or detached); supports
-p(publish ports) and-v(volumes) - Create — Create a box from an image or prepared rootfs without running; supports
-pand-v - Lifecycle — Start, stop, restart, remove boxes
- Inspect — Show detailed box info (JSON, YAML, or Go template)
- Exec — Run commands in a running or safely resumable box
- Images — Pull and list OCI images
- Copy — Copy files between host and box (
boxlite cp) - Output formats — Table, JSON, or YAML for list/images
- Shell completion — Bash, Zsh, Fish
Installation
One-line install (Linux & macOS Apple Silicon)
|
Installs to $HOME/.local/bin/boxlite. For version pinning, a custom
install dir, and release-artifact verification (sigstore, SHA256SUMS,
gh attestation verify), see the CLI Reference's Installation & Verification section.
cargo install (from source)
cargo binstall (prebuilt binary)
Homebrew
Coming soon
Build from Source
# From repository root
# Initialize submodules (required)
# Build the CLI
# Binary: target/release/boxlite
System Requirements
| Platform | Architecture | Status |
|---|---|---|
| macOS | Apple Silicon (ARM64) | ✅ Supported |
| Linux | x86_64 | ✅ Supported |
| Linux | ARM64 | ✅ Supported |
| Windows (WSL2) | x86_64 | ✅ Supported |
| macOS | Intel (x86_64) | ❌ Not supported |
Quick Start
Run a one-off command
Run interactively with a TTY
Create a box and run in the background
# Create and start (prints box ID)
# Run a command in the box
# List boxes
# Stop and remove
Pull an image and list images
Connecting to a remote server
To target a remote BoxLite REST server instead of the local runtime, sign in
with boxlite auth login. Three login methods are supported:
| Method | When to use | Token type |
|---|---|---|
api-key |
CI / automation, or a server-minted long-lived key | Opaque blk_… key |
browser |
Local developer machine with a desktop browser | OIDC access token |
device |
SSH session / headless container with no browser | OIDC access token |
Credential precedence is BOXLITE_API_KEY env > stored file > unauthenticated (local runtime).
The --url flag overrides the URL specifically without affecting credentials.
Multiple profiles coexist in one file via --profile <name> (or BOXLITE_PROFILE env var).
# Browser OIDC against a control plane (default for `auth login` on a TTY).
# Requires the IdP admin to have registered `http://127.0.0.1:5555/callback`
# in the SPA application's Allowed Callback URLs — see apps/infra/README.md
# "Callback URL mismatch" for the one-time setup.
# Same target, headless (SSH / no browser): prints a code + URL to type into
# any browser on another device.
# Local boxlite serve with a static API key (unchanged from the original behavior).
|
# CI via env vars only — no `auth login` call needed.
BOXLITE_API_KEY= BOXLITE_REST_URL=https://<your-server> boxlite
Credentials are stored at <BOXLITE_HOME>/credentials.toml (default
~/.boxlite/credentials.toml, perms 0600). OIDC
sessions auto-refresh on use when within 5 minutes of expiry; if the refresh
token is rejected (invalid_grant) the CLI prompts you to re-run auth login.
Commands Reference
For an exhaustive man-page-style reference (shared flag groups, volume/port grammar, exit codes, configuration file format), see the CLI Reference.
Global flags
Place these options before the top-level command or after the complete command
path. A parent command accepts only options shared by all of its children, so
write boxlite auth status --url URL (or boxlite --url URL auth status), not
boxlite auth --url URL status. Each command's help shows only options it can
use. Executing invocations reject unsupported options; Clap's --help and
--version display actions remain terminal.
| Flag | Scope | Description |
|---|---|---|
--debug |
all commands except completion |
Enable debug output. Precedence: --debug > RUST_LOG env > default (warn). |
--home PATH |
local runtime + credentials | Absolute BoxLite home directory (default: ~/.boxlite). BOXLITE_HOME is the env spelling. |
--registry REGISTRY |
run, create, pull, serve |
Image registry (repeatable; prepended to config). |
--config PATH |
local-capable commands | JSON config file path (e.g. for home_dir and image_registries). |
--url URL |
REST-capable commands | Connect to a remote BoxLite REST server instead of the local runtime. Env: BOXLITE_REST_URL. |
--profile NAME |
REST-capable commands + auth |
Named credential profile in <BOXLITE_HOME>/credentials.toml. Default default. Env: BOXLITE_PROFILE. |
--path-prefix VALUE |
REST box/volume commands | Routing-slot value for /v1/<prefix>/...; overrides the selected profile. Env: BOXLITE_REST_PATH_PREFIX. |
boxlite auth login
Log in to a BoxLite REST server. Supports three flows that all save to
<BOXLITE_HOME>/credentials.toml (default ~/.boxlite/credentials.toml,
perms 0600):
- API key — paste or stdin. Long-lived, org-scoped. Good for CI, SDK
integrations,
boxlite servesetups. - Browser OIDC — Authorization Code + PKCE against the IdP that
apps/apiis configured for (Auth0, Dex, Okta, etc.). Opens the system browser; the CLI listens on127.0.0.1:5555for the callback. Mints an access token + refresh token; the latter is used to silently refresh within 5 minutes of expiry. - Device code OIDC — RFC 8628. Headless / SSH-friendly: prints a short code + URL to enter on any browser on another device. Same token type and refresh behavior as the browser flow.
On a BoxLite Auth0 deployment, an existing unverified database account must complete the hosted verification Form through browser login:
Auth0 Forms cannot run inside refresh-token, device-code, or other non-interactive exchanges. An SSH user should finish verification through the BoxLite dashboard in a separate browser, then retry the device login.
When --method is unset, the CLI infers it: piped stdin → api-key (CI-safe),
while a TTY opens the interactive picker. If Browser is selected from that
picker in a detected headless/SSH environment, the CLI falls back to device.
Usage: boxlite auth login [OPTIONS]
| Option | Description |
|---|---|
--url URL |
Server URL (precedence: flag, BOXLITE_REST_URL, selected profile URL, then http://localhost:8100). For cloud control planes include the /api prefix. |
--method <api-key|browser|device> |
Explicit flow choice. Overrides inference. |
--api-key-stdin |
Read the API key from stdin (one line). The flag takes no value, so the secret never appears on argv. Selects API-key login and conflicts with explicit browser/device methods. |
--no-browser |
Use device code when no method is explicit; conflicts with API-key stdin and explicit API-key/browser methods. |
--callback-port <PORT> |
Local port for the browser-flow callback (default 5555). Must match an entry in the IdP's allow-list byte-for-byte — a different port produces "Callback URL mismatch" exactly like no entry at all. |
--issuer URL |
OIDC issuer URL. Overrides what GET /api/config returns. Useful for self-hosted Dex tenants where the discovery is wrong. |
--client-id ID |
OIDC client_id. Overrides /api/config. |
--audience VAL |
OIDC audience. Auth0 requires it; Dex tolerates None. |
--profile NAME selects the credential profile (default default), and
--home PATH selects the credential-store root.
Examples:
# Cloud control plane via browser (most common; opens system browser).
# Same target, headless: prints a code + URL.
# Local boxlite serve with paste-API-key (interactive).
# CI: API key from stdin (nothing on argv).
|
Deployment-side setup (one-time, by the IdP admin):
Browser and device flows fail with "Callback URL mismatch" until the IdP
knows about the CLI's loopback URL. For Auth0 see
apps/infra/README.md "Callback URL mismatch" — add
http://127.0.0.1:5555/callback to the SPA Application's
Allowed Callback URLs. For Dex see apps/dex/config.yaml — the same
URL goes under the boxlite static client's redirectURIs, plus
oauth2.deviceFlow: {} at the top level for device flow.
boxlite auth logout
Remove the selected profile from <BOXLITE_HOME>/credentials.toml (default
~/.boxlite/credentials.toml). Prompts for confirmation unless --yes is given.
Usage: boxlite auth logout [OPTIONS]
| Option | Short | Description |
|---|---|---|
--yes |
-y |
Skip the confirmation prompt |
boxlite auth status
Print the current authentication state: the logged-in URL, the source (stored file vs env var), the credential type (API key vs OIDC), and for OIDC sessions the access token's expiry. Offline — no network calls, no secret material printed.
Usage: boxlite auth status [--url URL] [--profile NAME]
Example output (API key):
Logged in to: http://localhost:8100
Credential: API key (from <BOXLITE_HOME>/credentials.toml [local])
Example output (OIDC session):
Logged in to: https://api.boxlite.ai/api
Credential: OIDC bearer token (from <BOXLITE_HOME>/credentials.toml [cloud])
Expires: 2026-05-21T15:42:00+00:00
boxlite auth whoami
Confirm the active credential's identity by making one authenticated
request to GET /v1/me. Unlike auth status (offline, only reports where
the credential came from), whoami shows the server-resolved principal,
path prefix, and scopes. Triggers a silent OIDC refresh if the access
token is within 5 minutes of expiry.
Usage: boxlite auth whoami [--url URL] [--profile NAME]
Example output:
Logged in as: dev@acme.test
Name: Dev McAcme
Principal: auth0|abc123 (user)
Path prefix: acme
Server: https://api.boxlite.ai/api
Scopes: box:read, box:write, box:exec, image:read, snapshot:read
boxlite run
Create a box from an image (or a prepared rootfs via --rootfs) and run a
command, with docker's semantics: COMMAND replaces the image's CMD, the
image's ENTRYPOINT is prepended, and the result is the container's init
(PID 1). Omit it and the image's own default runs.
The box lives exactly as long as that command. When it exits, the box stops and
takes its exit code — boxlite inspect -f '{{.State.ExitCode}}' NAME reads it
back. exec against a box whose command has finished is refused rather than
silently restarting it, because restarting would run the command a second time.
Usage:
boxlite run [OPTIONS] IMAGE [COMMAND]...boxlite run [OPTIONS] --rootfs PATH [COMMAND]...
| Option | Short | Description |
|---|---|---|
--rootfs PATH |
Use a prepared rootfs path instead of pulling/resolving an image | |
--interactive |
-i |
Keep STDIN open; conflicts with --detach |
--tty |
-t |
Allocate a pseudo-TTY; requires TTY-attached stdin, even with --detach |
--env KEY[=VALUE] |
-e |
Set environment variables; a bare key inherits its host value (repeatable) |
--workdir PATH |
-w |
Working directory in the box |
--user NAME[:GROUP] |
-u |
Run as a name/uid and optional group/gid |
--entrypoint EXEC |
Override the image entrypoint | |
--publish PORT |
-p |
Publish a TCP box port locally (80 = automatic host port, 8080:80 = fixed) |
--volume VOLUME |
-v |
Mount a volume: name:/box for a managed volume, ./path:/box for a host bind, /box for anonymous |
--cpus N |
CPU limit | |
--memory MiB |
Memory limit (MiB) | |
--disk-size GB |
Sparse rootfs disk size; smaller values than the base image are ignored | |
--cap-add CAPABILITY |
Add a Linux capability (repeatable; accepts CAP_ prefix or ALL) |
|
--cap-drop CAPABILITY |
Drop a Linux capability (repeatable; accepts CAP_ prefix or ALL) |
|
--network <enabled|disabled> |
Outbound network mode (default enabled) |
|
--allow-net HOST |
Restrict egress to an exact host, wildcard domain, IP, or CIDR; repeatable and implies enabled networking | |
--inbound <enabled|disabled> |
Inbound network mode (default enabled) |
|
--net-tx-kbps KBPS |
Cap what the box sends, in kilobits/sec; 0 or unset is uncapped. Local runtime only; verified on Linux |
|
--net-rx-kbps KBPS |
Cap what reaches the box, in kilobits/sec; 0 or unset is uncapped. Local runtime only; verified on Linux |
|
--name NAME |
Name the box | |
--detach |
-d |
Run in background, print box ID |
--rm |
Remove the box when it stops; conflicts with lifecycle deadlines and is ignored with --detach |
|
--auto-stop DURATION |
Stop the box after this much inactivity; 0 disables |
|
--auto-delete DURATION |
Delete the box this long after it stops; 0 disables |
|
--no-auto-resume |
Ask a REST server to refuse implicit resume after a box has run; first boot is unaffected, and the embedded runtime records but does not enforce it | |
--security <enable|disable> |
Embedded-runtime sandbox security (default enable; env BOXLITE_SECURITY); REST servers own this policy |
-p is explicit local publication. Remote REST profiles reject it and direct
the caller to boxlite network tunnel.
DURATION is seconds when bare, or suffixed: 30s, 15m, 2h, 7d. The two
deadlines are swept by a server — boxlite serve or the cloud — so against the
embedded runtime they are refused rather than silently reinterpreted. See the
CLI reference for the sweep's granularity
and how --rm differs between the two.
Examples:
boxlite create
Create a box without starting it.
COMMAND is stored, not run — it becomes the box's main command when the box is
next started, exactly as under run. A box created with one is a job, and
exec/cp will not start it implicitly (that would run the command); start it
deliberately with boxlite start. A box created without one boots the image's
default, and exec still starts it on demand.
Usage:
boxlite create [OPTIONS] IMAGE [COMMAND]...boxlite create [OPTIONS] --rootfs PATH [COMMAND]...
| Option | Short | Description |
|---|---|---|
--rootfs PATH |
Use a prepared rootfs path instead of pulling/resolving an image | |
--name NAME |
Name the box | |
--env KEY[=VALUE] |
-e |
Environment variables; a bare key inherits its host value |
--workdir PATH |
-w |
Working directory |
--entrypoint EXEC |
Override the image entrypoint | |
--publish PORT |
-p |
Publish a TCP box port locally (80 = automatic host port, 8080:80 = fixed) |
--volume VOLUME |
-v |
Mount a volume: name:/box for a managed volume, ./path:/box for a host bind, /box for anonymous |
--cpus N |
CPU limit | |
--memory MiB |
Memory limit (MiB) | |
--disk-size GB |
Sparse rootfs disk size; smaller values than the base image are ignored | |
--cap-add CAPABILITY |
Add a Linux capability (repeatable; accepts CAP_ prefix or ALL) |
|
--cap-drop CAPABILITY |
Drop a Linux capability (repeatable; accepts CAP_ prefix or ALL) |
|
--network <enabled|disabled> |
Outbound network mode (default enabled) |
|
--allow-net HOST |
Restrict egress to an exact host, wildcard domain, IP, or CIDR; repeatable and implies enabled networking | |
--inbound <enabled|disabled> |
Inbound network mode (default enabled) |
|
--net-tx-kbps KBPS |
Cap what the box sends, in kilobits/sec; 0 or unset is uncapped. Local runtime only; verified on Linux |
|
--net-rx-kbps KBPS |
Cap what reaches the box, in kilobits/sec; 0 or unset is uncapped. Local runtime only; verified on Linux |
|
--auto-stop DURATION |
Stop the box after this much inactivity; 0 disables; requires a REST server |
|
--auto-delete DURATION |
Delete the box this long after it stops; 0 disables; requires a REST server |
|
--no-auto-resume |
Ask a REST server to refuse implicit resume after a box has run; first boot is unaffected, and the embedded runtime records but does not enforce it | |
--security <enable|disable> |
Embedded-runtime sandbox security (default enable; env BOXLITE_SECURITY); REST servers own this policy |
-p is explicit local publication. Remote REST profiles reject it and direct
the caller to boxlite network tunnel.
Examples:
boxlite exec
Run a command in a box. A safely resumable stopped box starts implicitly; a
job box whose start would run or re-run its user-selected main command is
refused, so start that box deliberately with boxlite start first.
Usage: boxlite exec [OPTIONS] BOX -- COMMAND [ARGS]...
| Option | Short | Description |
|---|---|---|
--interactive |
-i |
Keep STDIN open; conflicts with --detach |
--tty |
-t |
Allocate a TTY; foreground mode requires TTY-attached stdin, while detached mode attaches no stdin |
--env KEY[=VALUE] |
-e |
Environment variables; a bare key inherits its host value |
--workdir PATH |
-w |
Working directory |
--user NAME[:GROUP] |
-u |
Run as a name/uid and optional group/gid |
--detach |
-d |
Run in background (don’t wait) |
Example:
boxlite list (alias: ls, ps)
List boxes.
Usage: boxlite list [OPTIONS]
| Option | Short | Description |
|---|---|---|
--all |
-a |
Show all boxes (default: running only) |
--quiet |
-q |
Show only IDs; conflicts with --format |
--format FMT |
Output format: table, json, yaml; conflicts with --quiet (default: table) |
boxlite start
Start one or more stopped boxes.
Usage: boxlite start BOX [BOX ...]
boxlite stop
Stop one or more running boxes.
Usage: boxlite stop BOX [BOX ...]
boxlite restart
Restart one or more boxes.
Usage: boxlite restart BOX [BOX ...]
boxlite rm
Remove one or more boxes.
Usage: boxlite rm [OPTIONS] BOX [BOX ...] or boxlite rm [OPTIONS] --all
| Option | Short | Description |
|---|---|---|
--force |
-f |
Force remove (e.g. running box) |
--all |
-a |
Remove all boxes (prompts unless --force) |
boxlite pull
Pull an image from a registry.
Usage: boxlite pull [OPTIONS] IMAGE
| Option | Short | Description |
|---|---|---|
--quiet |
-q |
Only print digest |
boxlite inspect
Display detailed information on one or more boxes (JSON, YAML, or Go-style template).
Usage: boxlite inspect [OPTIONS] [BOX ...] or boxlite inspect --latest
| Option | Short | Description |
|---|---|---|
--latest |
-l |
Inspect the most recently created box (cannot be used with BOX) |
--format FMT |
-f |
Output: json, yaml, or a Go template (e.g. {{.State.Status}}, {{.Id}}). Default: json. Table format is not supported. |
Examples:
boxlite images
List cached images.
Usage: boxlite images [OPTIONS]
| Option | Short | Description |
|---|---|---|
--quiet |
-q |
Show only image IDs; conflicts with --format |
--format FMT |
Output format: table, json, yaml; conflicts with --quiet |
boxlite cp
Copy files or directories between host and box.
Usage: boxlite cp [OPTIONS] SRC DST
- SRC / DST: host path or
BOX:PATH(e.g.mybox:/app/data).
| Option | Description |
|---|---|
--follow-symlinks |
Follow symlinks when copying (local runtime only) |
--no-overwrite |
Do not overwrite existing files (local runtime only) |
--no-include-parent |
Copy directory contents without their parent (local runtime only) |
Examples:
Paths at or under a mount inside the box are refused in both directions — /tmp,
/dev/shm, volumes, and the /etc/hosts, /etc/hostname, /etc/resolv.conf binds.
cp works on the rootfs layer from outside the box's mount namespace, so such a
copy would write where nothing in the box can see it, or read back the image's file
rather than the one the box has.
A directory that merely contains a mount differs by direction: copying one out is
refused (boxlite cp box:/etc ./etc), while copying in is allowed and refused only
if a file would land on a mount — so boxlite cp ./x box:/etc works.
Copy a path outside the mount, or pipe a tar through
boxlite exec. Files copied in are owned by the box's exec user.
boxlite info
Display system-wide runtime information (version, paths, host/virtualization, box and image counts). Default output is YAML.
Usage: boxlite info [OPTIONS]
| Option | Description |
|---|---|
--format FMT |
Output format: yaml, json (default: yaml). Table format is not supported. |
Output fields: version, homeDir, virtualization, os, arch, boxesTotal, boxesRunning, boxesStopped, boxesConfigured, imagesCount.
Examples:
Shell completion
Generate completion scripts for your shell:
# Bash
# or for current user
# Zsh
# Fish
Then reload your shell or source the file.
Environment variables
| Variable | Description |
|---|---|
BOXLITE_HOME |
Runtime and credential home directory (default: ~/.boxlite). Overridden by --home. |
BOXLITE_REST_URL |
REST server endpoint; equivalent to --url. |
BOXLITE_API_KEY |
Long-lived API key sent as Authorization: Bearer. Overrides any stored credentials. |
BOXLITE_PROFILE |
Credential profile; equivalent to --profile (default default). |
BOXLITE_REST_PATH_PREFIX |
REST routing path segment; equivalent to --path-prefix. |
BOXLITE_SECURITY |
run/create sandbox preset; equivalent to --security. |
BOXLITE_SERVE_API_KEY |
Expected bearer key for serve; equivalent to serve --api-key. |
OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_AUDIENCE |
OIDC login fallbacks after flags and server discovery. |
BOXLITE_LOG_FILE |
Explicit JSON log-file path for any command; serve otherwise defaults to <BOXLITE_HOME>/logs/serve.log. |
BOXLITE_EXPERIMENTAL |
Comma-separated RC features: custom-kernel, nested-virtualization. |
BOXLITE_RECONNECT_GRACE |
serve reconnect grace (default 5m). |
BOXLITE_SHUTDOWN_GRACE |
serve shutdown-stage grace (default 30s). |
BOXLITE_MAX_SESSION_LIFETIME |
serve session hard cap (default 24h). |
SSH_CONNECTION |
auth login headless detection; choosing Browser from the TTY picker falls back to device flow when set. |
RUST_LOG |
Log level: trace, debug, info, warn, error. Use RUST_LOG=debug for troubleshooting. |
Configuration file
Use --config PATH to load a JSON config file. Useful for default registries and other options. See Image registry configuration for details.
Troubleshooting
Image pull fails
- Check network and registry access.
- For private registries, see Image registry configuration for details.
- "Failed to pull manifest" or "error sending request for url" (e.g. to
index.docker.io): often network-related or Docker Hub rate limit/access in some regions. Retry later, use a mirror, or configure registries via--registry/--config. See issue #190 for discussion. - Enable debug output:
boxlite --debug pull IMAGEorRUST_LOG=debug boxlite pull IMAGE.
Box fails to start
- Enable debug output:
boxlite --debug run IMAGE [COMMAND]...orRUST_LOG=debug boxlite run IMAGE [COMMAND]....
Further documentation
- BoxLite README — Project overview and SDK quick starts
- Getting started — Prerequisites and platform setup
- Reference — Python, Node, Rust, C API reference
License
Licensed under the Apache License, Version 2.0. See LICENSE for details.