> ## Documentation Index
> Fetch the complete documentation index at: https://isol8.notdhruv.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to CLI

> Detailed command-line guide for isol8 with flag-by-flag behavior for run, setup, build, serve, config, and cleanup commands.

<Callout type="info">
  **Migration**: CLI is now `@isol8/cli` (installed as `isol8` command).
</Callout>

This page is a flag-by-flag reference for the `isol8` CLI.

## Global option

<ResponseField name="--debug" type="flag">
  Enables debug logs for CLI internals and engine operations.
</ResponseField>

## `isol8 run`

```bash theme={null}
isol8 run [file] [options]
```

<Info>
  `isol8 run` streams output by default. Use `--no-stream` only when you want buffered output after execution completes.
</Info>

### Input and runtime flags

<ResponseField name="[file]" type="argument">
  Script file path. Runtime is auto-detected from extension unless `--runtime` is provided.
</ResponseField>

<ResponseField name="-e, --eval <code>" type="string">
  Inline code to execute.
</ResponseField>

<ResponseField name="-r, --runtime <name>" type="python | node | bun | deno | bash | agent">
  Force runtime instead of extension-based detection. The `agent` runtime must always be specified explicitly (no file extension mapping).
</ResponseField>

<ResponseField name="--stdin <data>" type="string">
  Explicit stdin payload for the execution process.
</ResponseField>

<ResponseField name="--workdir <path>" type="string" default="/sandbox">
  Working directory for the main code execution. Accepts an absolute path under `/sandbox` or a
  relative path resolved from `/sandbox`. Paths that escape the sandbox boundary are rejected.
</ResponseField>

### Security and resource flags

<ResponseField name="--net <mode>" type="none | host | filtered" default="none">
  Sets the network egress mode for the container.

  * `none`: Blocks all network access (default).
  * `filtered`: Routes traffic through a proxy with whitelist/blacklist enforcement.
  * `host`: Allows full host network access (use with extreme caution).

  If `--install` is used and `--net` is not explicitly provided, CLI automatically uses `filtered`.
</ResponseField>

<Warning>
  `--net host` gives untrusted code full outbound network access. Prefer `none` (default) or `filtered` for most workloads.
</Warning>

<ResponseField name="--allow <regex>" type="repeatable">
  Adds a regex pattern to the whitelist in `filtered` mode. Only hostnames matching at least one allow pattern will be permitted.
</ResponseField>

<ResponseField name="--deny <regex>" type="repeatable">
  Blacklist pattern for filtered mode.
</ResponseField>

<ResponseField name="--timeout <ms>" type="number">
  Timeout in milliseconds for package installation and code execution.
</ResponseField>

<ResponseField name="--memory <size>" type="string">
  Memory limit (`512m`, `1g`, etc.).
</ResponseField>

<ResponseField name="--cpu <limit>" type="number">
  CPU limit as fraction/cores.
</ResponseField>

<ResponseField name="--pids-limit <n>" type="number" default="64">
  Maximum number of processes.
</ResponseField>

<ResponseField name="--max-output <bytes>" type="number" default="1048576">
  Maximum output size before truncation.
</ResponseField>

<ResponseField name="--sandbox-size <size>" type="string" default="512m">
  `/sandbox` tmpfs size.
</ResponseField>

<ResponseField name="--tmp-size <size>" type="string" default="256m">
  `/tmp` tmpfs size.
</ResponseField>

### State and behavior flags

<ResponseField name="--persistent" type="flag">
  Use persistent mode (`mode=persistent`).
</ResponseField>

<ResponseField name="--persist" type="flag">
  Keep container alive after execution finishes.
</ResponseField>

<ResponseField name="--no-stream" type="flag">
  Disable realtime streaming and use buffered `execute()` path.
</ResponseField>

<ResponseField name="--install <package>" type="repeatable">
  Install package before execution.

  In `filtered` mode, CLI automatically merges default runtime package registry hosts into the allowlist.
  Explicit `--net` is never overridden.
</ResponseField>

<ResponseField name="--setup <command>" type="repeatable">
  Inline shell command or path to a script file to run before the main code execution. Runs as the
  `sandbox` user from `/sandbox`. If the value is an existing file path, its contents are read and
  used as the script. Multiple `--setup` flags are concatenated with newlines. Useful for cloning
  repos, creating directories, configuring tools, etc.
</ResponseField>

<ResponseField name="--secret <KEY=VALUE>" type="repeatable">
  Inject secret env vars and mask values in output.
</ResponseField>

<ResponseField name="--agent-flags <flags>" type="string">
  Extra flags passed to the `pi` coding agent before the prompt. Only valid with `--runtime agent`.
  Common flags: `--model <name>`, `--thinking`, `--max-tokens <n>`.
</ResponseField>

<ResponseField name="--files <dir>" type="string">
  Recursively inject a local directory into the container under `/sandbox`. Skips `.git`, `node_modules`, `__pycache__`, `.venv`, `venv`, and `.tox` directories. Useful with the `agent` runtime to provide project files for the agent to work on.
</ResponseField>

<ResponseField name="--out <file>" type="string">
  Write stdout to local file.
</ResponseField>

<ResponseField name="--image <name>" type="string">
  Override runtime image.
</ResponseField>

<ResponseField name="--log-network" type="flag">
  Enable network request logs in results (filtered mode).
</ResponseField>

### Remote execution flags

<ResponseField name="--host <url>" type="string">
  Execute against remote `isol8 serve` instance.
</ResponseField>

<ResponseField name="--key <key>" type="string">
  API key for remote execution (`ISOL8_API_KEY` fallback).
</ResponseField>

<ResponseField name="--session-id <id>" type="string">
  Use a named persistent session on the remote server. The session survives after the CLI exits and can be resumed by passing the same ID again.

  Implies `--persistent` — you do not need to pass both.
  Requires `--host` — session IDs are a server-side concept.
</ResponseField>

### Examples

```bash theme={null}
# Inline Python
isol8 run \
  -e "print(2 ** 10)" \
  --runtime python

# Filtered networking
isol8 run \
  task.py \
  --net filtered \
  --allow "^api\.openai\.com$"

# Persistent mode
isol8 run \
  --persistent \
  -e "x = 42" \
  --runtime python

# Remote execution
isol8 run \
  script.py \
  --host http://localhost:3000 \
  --key my-key

# Named session — survives after CLI exits
isol8 run \
  -e "x = 42" \
  --runtime python \
  --session-id my-session \
  --host http://localhost:3000 \
  --key my-key

# Resume the same session later
isol8 run \
  -e "print(x)" \
  --runtime python \
  --session-id my-session \
  --host http://localhost:3000 \
  --key my-key

# AI coding agent
isol8 run \
  -e "add error handling to all API endpoints" \
  --runtime agent \
  --net filtered --allow "api.anthropic.com" \
  --secret "ANTHROPIC_API_KEY=sk-..." \
  --files ./my-project \
  --workdir /sandbox/my-project \
  --timeout 600000

# Agent with extra pi flags
isol8 run \
  -e "refactor auth module" \
  --runtime agent \
  --net filtered --allow "api.anthropic.com" \
  --secret "ANTHROPIC_API_KEY=sk-..." \
  --files ./src \
  --agent-flags "--model claude-sonnet-4-20250514 --thinking"
```

## `isol8 setup`

```bash theme={null}
isol8 setup [options]
```

Builds base isol8 Docker images and any `prebuiltImages` declared in `isol8.config.json`.

<ResponseField name="--force" type="flag">
  Force rebuild even when images are up to date.
</ResponseField>

<Info>
  If your config defines `prebuiltImages`, `isol8 setup` will also check each one and build any that don't already exist locally.
</Info>

## `isol8 serve`

```bash theme={null}
isol8 serve --key <api-key> [options]
```

<ResponseField name="-p, --port <port>" type="number" default="3000">
  Port for server listener. Resolution order is `--port` > `ISOL8_PORT` > `PORT` > `3000`.
  If the selected port is occupied, the CLI prompts to choose a different port or automatically finds an available one.
</ResponseField>

<ResponseField name="-k, --key <key>" type="string">
  API key for bearer auth. If omitted, `ISOL8_API_KEY` environment variable is used.
  When `--auth-db` is also provided, this key becomes the **master key** with admin privileges.
</ResponseField>

<ResponseField name="--auth-db [connection]" type="string">
  Enable DB-backed API key management. When provided without a value or with a file path, uses SQLite (defaults to `~/.isol8/auth.db`).
  Pass a `postgres://` or `postgresql://` URL for PostgreSQL, or a `mysql://` URL for MySQL.
  The backend is auto-detected from the connection string format.
  When enabled, the `--key` value becomes the master key, and additional keys can be created
  via the `/auth/keys` endpoint or the `isol8 login` flow. See <a href="/server/overview">Server overview</a> for the full authentication model.
</ResponseField>

<ResponseField name="--update" type="flag">
  Force re-download of standalone server binary.
</ResponseField>

<ResponseField name="--debug" type="flag">
  Enable debug logs for server internals.
</ResponseField>

### Examples

```bash theme={null}
# Static key auth (default)
isol8 serve --key my-secret-key --port 3000

# DB-backed auth with SQLite (default path ~/.isol8/auth.db)
isol8 serve --key my-master-key --auth-db --port 3000

# DB-backed auth with SQLite (custom path)
isol8 serve --key my-master-key --auth-db ./isol8-auth.db --port 3000

# DB-backed auth with PostgreSQL
isol8 serve --key my-master-key --auth-db "postgres://user:pass@localhost:5432/isol8" --port 3000

# DB-backed auth with MySQL
isol8 serve --key my-master-key --auth-db "mysql://user:pass@localhost:3306/isol8" --port 3000
```

<Info>
  For full server behavior and endpoints, see the Server docs tab: <a href="/server/overview">Server overview</a> and <a href="/server/routes">Server routes</a>.
</Info>

## `isol8 login`

```bash theme={null}
isol8 login --host <url> --key <master-key> [options]
```

Authenticate with a remote isol8 server that has DB-backed auth enabled. This command exchanges the master key for a short-lived API token via `POST /auth/login` and stores the credentials locally.

<ResponseField name="--host <url>" type="string" required>
  Server URL to authenticate against (e.g. `http://localhost:3000`).
</ResponseField>

<ResponseField name="--key <key>" type="string" required>
  Master API key for the server. This is the same key passed to `isol8 serve --key`.
</ResponseField>

<ResponseField name="--name <name>" type="string">
  Optional human-readable name for the login token. Defaults to `cli-login-<timestamp>`.
</ResponseField>

<ResponseField name="--ttl <ms>" type="number">
  Token time-to-live in milliseconds. Defaults to 24 hours (`86400000`).
</ResponseField>

Once authenticated, credentials are saved to `~/.isol8/credentials.json` (file permissions `0600`). Subsequent `isol8 run --host <url>` commands automatically use the stored token without needing `--key`.

### Credential resolution priority

When running remote commands (`isol8 run --host ...`), the CLI resolves the API key in this order:

1. `--key` flag (explicit, always wins)
2. `ISOL8_API_KEY` environment variable
3. Stored credentials from `~/.isol8/credentials.json` (if host matches and token is not expired)

### Examples

```bash theme={null}
# Login to a local server
isol8 login --host http://localhost:3000 --key my-master-key

# Login with custom name and TTL
isol8 login \
  --host https://isol8.example.com \
  --key my-master-key \
  --name "dev-laptop" \
  --ttl 3600000

# After login, --key is no longer needed for this host
isol8 run -e "print('hello')" \
  --runtime python \
  --host http://localhost:3000
```

<Warning>
  The server must have `--auth-db` enabled. If DB-backed auth is not active, `isol8 login` will fail with a `400` error.
</Warning>

## `isol8 logout`

```bash theme={null}
isol8 logout
```

Remove stored credentials from `~/.isol8/credentials.json`. This does not revoke the token on the server — it only deletes the local credential file.

### Examples

```bash theme={null}
isol8 logout
# [OK] Credentials removed from ~/.isol8/credentials.json
```

## `isol8 session`

Manage persistent sessions on a remote server.

### `isol8 session list`

```bash theme={null}
isol8 session list --host <url> [--key <key>] [--json]
```

Lists all active persistent sessions on the remote server.

<ResponseField name="--host <url>" type="string" required>
  Remote server URL.
</ResponseField>

<ResponseField name="--key <key>" type="string">
  API key (`ISOL8_API_KEY` fallback, or stored credentials from `isol8 login`).
</ResponseField>

<ResponseField name="--json" type="flag">
  Print raw JSON array instead of the formatted table.
</ResponseField>

#### Examples

```bash theme={null}
# Table output
isol8 session list --host http://localhost:3000 --key my-key

# JSON output
isol8 session list --host http://localhost:3000 --key my-key --json
```

### `isol8 session stop`

```bash theme={null}
isol8 session stop <id> --host <url> [--key <key>]
```

Destroys a specific persistent session on the remote server and releases its resources.

<ResponseField name="<id>" type="argument" required>
  Session ID to destroy.
</ResponseField>

<ResponseField name="--host <url>" type="string" required>
  Remote server URL.
</ResponseField>

<ResponseField name="--key <key>" type="string">
  API key (`ISOL8_API_KEY` fallback, or stored credentials from `isol8 login`).
</ResponseField>

#### Examples

```bash theme={null}
# Stop a named session
isol8 session stop my-session --host http://localhost:3000 --key my-key
```

## `isol8 build`

Build a custom runtime image with pre-baked dependencies and/or a setup script.

```bash theme={null}
isol8 build --base <runtime> [--install <package>] [--setup <command>] --tag <name> [options]
```

<ResponseField name="--base <runtime>" type="python | node | bun | deno | bash" required>
  Runtime base image to extend.
</ResponseField>

<ResponseField name="--install <package>" type="repeatable">
  Package to bake into the image. Supports repeated flags and comma-separated values.
</ResponseField>

<ResponseField name="--setup <command>" type="repeatable">
  Shell command or file path baked into the image. Runs automatically before every
  execution that uses this image.  When an execution request also carries its own
  `--setup`, the image-level script runs first followed by the request-level script.
  If the value points to an existing file, its content is read; otherwise the value
  is treated as a literal shell command.
</ResponseField>

<ResponseField name="--tag <name>" type="string" required>
  Name/tag for the custom image (e.g. `my-python-ml:latest`). Metadata labels are embedded automatically.
</ResponseField>

<ResponseField name="--force" type="flag">
  Force rebuild even if current inputs resolve to an existing up-to-date image.
</ResponseField>

### Examples

```bash theme={null}
# Build a custom Python image with ML packages
isol8 build --base python --install numpy --install pandas --tag my-python-ml

# Build a custom Node.js image
isol8 build --base node --install express,lodash --tag my-node-api

# Build with a setup script that runs before every execution
isol8 build --base python --install numpy --setup "pip install -e /sandbox/mylib" --tag my-python-dev

# Build with setup only (no packages)
isol8 build --base bash --setup "echo ready" --tag my-bash-env

# Force rebuild
isol8 build --base python --install numpy --tag my-python-ml --force
```

## `isol8 list-custom`

List all locally available custom isol8 images.

```bash theme={null}
isol8 list-custom
```

Displays each custom image's tag, runtime, pre-installed dependencies, and setup script (if any) based on embedded Docker labels.

## `isol8 config`

```bash theme={null}
isol8 config [options]
```

## `isol8 cleanup`

```bash theme={null}
isol8 cleanup [options]
```

<ResponseField name="--json" type="flag">
  Print resolved config as JSON.
</ResponseField>

## `isol8 cleanup`

```bash theme={null}
isol8 cleanup [options]
```

<ResponseField name="--force" type="flag">
  Skip confirmation prompt.
</ResponseField>

<ResponseField name="--images" type="flag">
  Also remove isol8 Docker images.
</ResponseField>

## FAQ

<Accordion title="What is the difference between `--persistent` and `--persist`?">
  `--persistent` sets execution mode to persistent (reuses container state across runs). `--persist` keeps the container alive after a run for inspection/debugging.
</Accordion>

<Accordion title="What is the difference between `--persistent` and `--session-id`?">
  `--persistent` creates a persistent session with an auto-generated ID that is destroyed when the CLI exits. `--session-id` assigns a user-chosen name and keeps the session alive on the server after the CLI exits, so you can reconnect later with the same ID.
</Accordion>

<Accordion title="Do I need `--key` for `isol8 serve` every time?">
  No. `isol8 serve` accepts `--key`, but it can also read the API key from `ISOL8_API_KEY`.
</Accordion>

<Accordion title="What is the difference between `--key` and `--auth-db`?">
  `--key` sets a single static API key (or master key). `--auth-db` enables database-backed key management (SQLite, PostgreSQL, or MySQL) where you can create, list, and revoke multiple keys via the `/auth/*` endpoints. Both can be used together — the `--key` becomes the master key when `--auth-db` is enabled.
</Accordion>

<Accordion title="Do I need to run `isol8 login` to use remote execution?">
  No. You can always pass `--key` explicitly or set `ISOL8_API_KEY`. `isol8 login` is a convenience that stores credentials locally so you don't have to provide the key on every command.
</Accordion>

<Accordion title="Why does `isol8 run` print output in real time?">
  Streaming is the default behavior. Use `--no-stream` if you want buffered output only after the run completes.
</Accordion>

<Accordion title="What is the agent runtime?">
  The `agent` runtime runs the [pi coding agent](https://github.com/mariozechner/pi-coding-agent) inside an isol8 sandbox. The `-e` value is treated as the prompt, not code. It requires `--net filtered` with an `--allow` entry for the LLM API, and an API key via `--secret`. The CLI automatically raises `pidsLimit` to 200 and `sandboxSize` to 2g for agent runs.
</Accordion>

## Troubleshooting quick checks

* **`[ERR] --session-id requires --host`**: `--session-id` is a server feature; add `--host <url>`.
* **`[ERR] API key required` on `serve` or remote `run`**: pass `--key` or set `ISOL8_API_KEY`.
* **`isol8 login` fails with 400**: the server does not have `--auth-db` enabled. Restart the server with `--auth-db <path>`.
* **Stored credentials expired**: run `isol8 login` again to re-authenticate.
* **Runtime not detected from file extension**: pass `--runtime <name>` explicitly.
* **No output appears while command runs**: check if `--no-stream` is enabled.
* **Filtered mode still blocks host**: verify `--allow` regex matches hostname exactly.
* **Agent runtime fails with network error**: ensure `--net filtered` and `--allow` are set. The agent runtime enforces filtered networking with at least one whitelist entry.
* **Agent runtime out of disk space**: increase `--sandbox-size` (default 2g for agent). Large repos may need 4g+.

## See also

<CardGroup cols={2}>
  <Card title="Option mapping" icon="sliders" href="/option-mapping">
    Map each CLI flag to config, API, and library equivalents.
  </Card>

  <Card title="Configuration reference" icon="settings" href="/configuration">
    Full config schema, defaults, and precedence rules.
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/troubleshooting">
    Diagnose and fix common CLI/runtime failures quickly.
  </Card>
</CardGroup>
