Skip to content
Open
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 40 additions & 5 deletions docs/reference/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,14 @@ takes the command's exit code; `boxlite ps` shows it stopped and

- Default (foreground): streams stdout/stderr to the terminal, exits with the box command's exit code. If the command was killed by signal *N*, exits with `128 + N` (Unix convention, see [Exit Codes](#exit-codes)).
- `-d`/`--detach`: prints the box ID to stdout and exits `0` immediately; `auto_remove` is force-disabled in this mode so the box outlives the CLI process.
- `--tty` with non-TTY stdin: fails with `the input device is not a TTY.`
- Foreground `--tty` with non-TTY stdin: fails with `the input device is not a TTY.` Detached `-d -t` is allowed because the command does not attach to local stdin.

**Examples:**

```bash
boxlite run alpine:latest echo "Hello"
boxlite run -it --rm alpine:latest /bin/sh
boxlite run --env-file .env -e DEBUG=1 python:slim python app.py
boxlite run -d --name web -p 8080:80 nginx:alpine
boxlite run -v $(pwd):/work -w /work alpine:latest ls -la
boxlite run --cpus 4 --memory 4096 python:slim python -c "print(2+2)"
Expand Down Expand Up @@ -291,6 +292,7 @@ Run a command in a *running* box. The `--` separator is required (`src/cli/src/c
boxlite exec mybox -- echo "hello"
boxlite exec -it mybox -- /bin/sh
boxlite exec -e DEBUG=1 -w /app mybox -- pytest tests/
boxlite exec --env-file test.env mybox -- pytest tests/
```

---
Expand Down Expand Up @@ -319,16 +321,20 @@ implicitly, because starting it runs that command. Start it deliberately with
|------|-------|-------------|
| `--rootfs PATH` | — | Use a prepared rootfs path instead of pulling/resolving an image |
| `--env KEY=VALUE` | `-e` | Set environment variables (repeatable) |
| `--env-file FILE` | — | Read environment variables from a file (repeatable) |
| `--workdir PATH` | `-w` | Working directory inside the box |

Also uses [`ResourceFlags`](#resourceflags) + [`PublishFlags`](#publishflags) + [`VolumeFlags`](#volumeflags) + [`ManagementFlags`](#managementflags).

> Note: `create` accepts `--env` and `--workdir` directly rather than via `ProcessFlags` (no `-i`/`-t`/`-u` here, since no command is being executed).
> Note: `create` flattens `EnvironmentFlags` directly and defines `--workdir`
> itself rather than using `ProcessFlags`; it therefore does not expose
> `-i`/`-t`/`-u`, since no command is executed.

**Examples:**

```bash
boxlite create --name mybox alpine:latest
boxlite create --env-file .env --name configured alpine:latest
boxlite create -p 8080:80 -v /data:/app/data --name web nginx:alpine
boxlite create --rootfs /path/to/rootfs --name local-rootfs
```
Expand Down Expand Up @@ -599,19 +605,48 @@ boxlite completion fish > ~/.config/fish/completions/boxlite.fish

Several commands flatten shared `clap` `Args` structs. Each is documented here once.

### `EnvironmentFlags`

Used by `run`, `create`, and `exec`.

| Flag | Short | Description |
|------|-------|-------------|
| `--env KEY=VALUE` | `-e` | Set an environment variable; a bare key inherits from the host |
| `--env-file FILE` | — | Read environment variables from a file; repeatable |

Environment behavior:

- **Syntax:** Environment files use dotenv syntax, including quoted values,
`export` prefixes, comments, escapes, and variable substitution. A UTF-8 BOM
at the start of a file is ignored.
- **Precedence:** Files are applied in command-line order. Later files override
earlier files, and explicit `-e` values have the highest precedence. During
substitution, host values take precedence over values defined earlier in the
same file. If the host variable is unset, an earlier same-file value is used.
- **Substitution scope:** Each file is evaluated independently, so references
cannot use values defined by an earlier `--env-file`.
- **Undefined substitutions:** An undefined reference expands to an empty string
without a warning. Escape `$` or use single quotes to preserve it literally.
- **Bare `-e` keys:** A bare key inherits its value from the host. If absent
there, it remains unset and removes any value loaded from an earlier
`--env-file`.
- **Secrets:** Environment-file values enter the guest. Use BoxLite secret
injection for credentials that must remain outside the VM.

### `ProcessFlags`

Used by `run` and `exec` (defined at `src/cli/src/cli.rs:208-281`).
Used by `run` and `exec` and includes [`EnvironmentFlags`](#environmentflags).

| Flag | Short | Description |
|------|-------|-------------|
| `--interactive` | `-i` | Keep STDIN open even if not attached |
| `--tty` | `-t` | Allocate a pseudo-TTY (stdout and stderr are merged in TTY mode) |
| `--env KEY=VALUE` | `-e` | Set environment variables (repeatable; if value omitted, inherits from host) |
| `--workdir PATH` | `-w` | Working directory inside the box |
| `--user NAME[:GROUP]` | `-u` | Run as `name`/`uid`[:`group`/`gid`] |

`--tty` implies `--interactive` when stdin is a TTY. `--tty` without a TTY-attached stdin is a hard error.
In foreground mode, `--tty` implies `--interactive` when stdin is a TTY and
fails when stdin is not a TTY. Detached `-d -t` is allowed because the command
does not attach to local stdin.

### `ResourceFlags`

Expand Down
1 change: 1 addition & 0 deletions src/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ futures = "0.3"
term_size = "0.3"
nix = { version = "0.30.1", features = ["term", "signal"] }
anyhow = "1.0"
dotenvy = "0.15.7"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter", "json"] }
tracing-appender = "0.2"
Expand Down
27 changes: 26 additions & 1 deletion src/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ silently restarting it, because restarting would run the command a second time.
| `--interactive` | `-i` | Keep STDIN open |
| `--tty` | `-t` | Allocate a pseudo-TTY |
| `--env KEY=VALUE` | `-e` | Set environment variables (repeatable) |
| `--env-file FILE` | | Read environment variables from a file (repeatable) |
| `--workdir PATH` | `-w` | Working directory in the box |
| `--publish PORT` | `-p` | Publish box port to host (e.g. `8080:80`, `8080:80/tcp`) |
| `--volume VOLUME` | `-v` | Mount a volume (e.g. `hostPath:boxPath`, `boxPath` for anonymous) |
Expand All @@ -331,6 +332,7 @@ silently restarting it, because restarting would run the command a second time.
```bash
boxlite run alpine:latest echo "Hello"
boxlite run -it --rm alpine:latest /bin/sh
boxlite run --env-file .env -e DEBUG=1 python:slim python app.py
boxlite run -d --name openclaw -p 18789:18789 ghcr.io/openclaw/openclaw:main
boxlite run -v /host/data:/app/data alpine:latest cat /app/data/hello.txt
boxlite run --rootfs /path/to/rootfs /bin/sh
Expand All @@ -356,6 +358,7 @@ default, and `exec` still starts it on demand.
| `--rootfs PATH` | | Use a prepared rootfs path instead of pulling/resolving an image |
| `--name NAME` | | Name the box |
| `--env KEY=VALUE` | `-e` | Environment variables |
| `--env-file FILE` | | Read environment variables from a file (repeatable) |
| `--workdir PATH` | `-w` | Working directory |
| `--publish PORT` | `-p` | Publish box port to host (e.g. `8080:80`) |
| `--volume VOLUME` | `-v` | Mount a volume (e.g. `hostPath:boxPath`, or box path for anonymous) |
Expand All @@ -368,6 +371,7 @@ default, and `exec` still starts it on demand.

```bash
boxlite create --name mybox alpine:latest
boxlite create --env-file .env --name configured alpine:latest
boxlite create -p 18789:18789 -v /data:/app/data --name openclaw ghcr.io/openclaw/openclaw:main
boxlite create --rootfs /path/to/rootfs --name local-rootfs
boxlite start mybox
Expand All @@ -385,15 +389,36 @@ Run a command in a running box.
| `--interactive` | `-i` | Keep STDIN open |
| `--tty` | `-t` | Allocate a TTY |
| `--env KEY=VALUE` | `-e` | Environment variables |
| `--env-file FILE` | | Read environment variables from a file (repeatable) |
| `--workdir PATH` | `-w` | Working directory |
| `--detach` | `-d` | Run in background (don’t wait) |

**Example:**

```bash
boxlite exec -it mybox /bin/sh
boxlite exec -it mybox -- /bin/sh
boxlite exec --env-file test.env mybox -- pytest
```

#### Environment behavior for `run`, `create`, and `exec`

- **Syntax:** Environment files use dotenv syntax, including quoted values,
`export` prefixes, comments, escapes, and variable substitution. A UTF-8 BOM
at the start of a file is ignored.
- **Precedence:** Later files override earlier files, and explicit `-e` values
override all files. During substitution, host values take precedence over
values defined earlier in the same file. If the host variable is unset, an
earlier same-file value is used.
- **Substitution scope:** Each file is evaluated independently, so references
cannot use values defined by an earlier `--env-file`.
- **Undefined substitutions:** An undefined reference expands to an empty string
without a warning. Escape `$` or use single quotes to preserve it literally.
- **Bare `-e` keys:** A bare key inherits its value from the host. If absent
there, it remains unset and removes any value loaded from an earlier
`--env-file`.
- **Secrets:** Environment-file values enter the box and should not replace
BoxLite secret injection.

### `boxlite list` (alias: `ls`, `ps`)

List boxes.
Expand Down
Loading