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 inside a running 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/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
Available for all commands:
| Flag | Description |
|---|---|
--debug |
Enable debug output. Precedence: --debug > RUST_LOG env > default (warn). |
--home PATH |
BoxLite home directory (default: ~/.boxlite). Overridden by BOXLITE_HOME |
--registry REGISTRY |
Image registry (repeatable; prepended to config) |
--config PATH |
JSON config file path (e.g. for image_registries) |
--url URL |
Connect to a remote BoxLite REST server instead of the local runtime. Env: BOXLITE_REST_URL. |
--profile NAME |
Named credential profile in ~/.boxlite/credentials.toml. Lets one machine hold separate logins (e.g. local for boxlite serve, cloud for a remote control plane). Default default. Env: BOXLITE_PROFILE. |
--path-prefix VALUE |
Routing-slot value for the URL path (/v1/<prefix>/boxes/...). Opaque — the server decides what it means (organization, workspace, catalog, …). Captured automatically at auth login time from Principal.path_prefix. This flag overrides the stored profile's value for credentials with scope over multiple routing values. Unset / empty → URL skips the segment (/v1/boxes/...), the canonical shape for single-tenant deployments like boxlite serve. Env: BOXLITE_REST_PATH_PREFIX. |
boxlite auth login
Log in to a BoxLite REST server. Supports three flows that all save to
~/.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),
TTY → interactive picker, $SSH_CONNECTION set → silent fallback to device.
Usage: boxlite auth login [OPTIONS]
| Option | Description |
|---|---|
--url URL |
Server URL (default: http://localhost:8100, matching boxlite serve). For cloud control planes include the /api prefix, e.g. https://api.example.com/api. |
--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. Implies --method api-key. |
--no-browser |
Skip the browser; use device code instead. Implies --method device. |
--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. |
Global flags also apply — most importantly --profile NAME to log in to a
specific credential profile (default default).
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 stored credentials at ~/.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 [--profile NAME]
Example output (API key):
Logged in to: http://localhost:8100
Credential: API key (from ~/.boxlite/credentials.toml [local])
Example output (OIDC session):
Logged in to: https://api.boxlite.ai/api
Credential: OIDC bearer token (from ~/.boxlite/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,
organization, and scopes. Triggers a silent OIDC refresh if the access
token is within 5 minutes of expiry.
Usage: boxlite auth whoami [--profile NAME]
Example output:
Logged in as: dev@acme.test
Name: Dev McAcme
Principal: auth0|abc123 (user)
Organization: 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 |
--tty |
-t |
Allocate a pseudo-TTY |
--env KEY=VALUE |
-e |
Set environment variables (repeatable) |
--workdir PATH |
-w |
Working directory in the box |
--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) | |
--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) |
|
--name NAME |
Name the box | |
--detach |
-d |
Run in background, print box ID |
--rm |
Remove the box when it exits |
-p is explicit local publication. Remote REST profiles reject it and direct
the caller to boxlite network tunnel.
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 |
--workdir PATH |
-w |
Working directory |
--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) | |
--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) |
|
--detach |
-d |
(create always “detaches”) |
--rm |
Auto-remove when stopped |
-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 running box.
Usage: boxlite exec [OPTIONS] BOX COMMAND [ARGS]...
| Option | Short | Description |
|---|---|---|
--interactive |
-i |
Keep STDIN open |
--tty |
-t |
Allocate a TTY |
--env KEY=VALUE |
-e |
Environment variables |
--workdir PATH |
-w |
Working directory |
--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 |
--format FMT |
Output format: table, json, yaml (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 |
|---|---|---|
--all |
-a |
Show all images (including intermediate) |
--quiet |
-q |
Show only image IDs |
--format FMT |
Output format: table, json, yaml |
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 |
--no-overwrite |
Do not overwrite existing files |
--include-parent |
Include parent directory when copying from box (default: true) |
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 home directory (default: ~/.boxlite). Overridden by --home. |
BOXLITE_API_KEY |
Long-lived API key sent as Authorization: Bearer. Overrides any stored credentials. |
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.