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

# 沙箱配置

> 配置 LangBot 沙箱（Box Runtime），设置隔离的代码执行后端：Docker、nsjail 或 E2B。

沙箱由 LangBot 主进程配置，Box Runtime 负责实际执行。常规部署只需要选择后端、设置工作目录和安全预设。

<Note>
  本页所有 `box.*` 配置都写在 `data/config.yaml` 中。配置文件的位置和加载机制详见[系统环境设置](../../deploy/settings)。
</Note>

## 推荐配置

```yaml theme={null}
box:
  enabled: true
  backend: 'local'        # 自动从 Docker / Nsjail 里选可用的
  local:
    profile: 'default'
    host_root: './data/box'
    skills_root: 'skills'
  docker:
    cpu_limit_enabled: true
```

* `enabled`：沙箱总开关。设为 `false` 时，沙箱内置工具、Skill 添加/编辑、stdio MCP 托管等依赖 Box 的能力都不可用。
* `backend`：见下文「后端选择」。
* `local.profile`：安全预设，控制网络、挂载和资源限制。
* `local.host_root`：主机上的沙箱工作目录，会映射为沙箱内的 `/workspace`。
* `local.skills_root`：Skill 包目录；相对路径解析到 `host_root` 下，默认 `host_root/skills`。
* `docker.cpu_limit_enabled`：是否为 Docker 沙箱容器启用 CPU 限制；设为 `false` 时不传 `docker run --cpus`，内存和 PID 限制仍然保留。

<Note>
  Skills 只从 Box Runtime 管理的 skill store 加载。Box Runtime 或后端不可用时 Skill 列表为空，新增 / 编辑 / `register_skill` 都不可用；不会回退扫描 `data/skills/`。
</Note>

## 后端选择

沙箱可以跑在**本机容器**或**云端**。`box.backend` 选择走哪一种：

| `backend`   | 跑在哪  | 行为                                       |
| ----------- | ---- | ---------------------------------------- |
| `local`（默认） | 本机容器 | 自动从 Docker / Nsjail 里选可用的（Docker 优先）     |
| `docker`    | 本机容器 | 强制使用 Docker，需要 Docker daemon             |
| `nsjail`    | 本机容器 | 强制使用 Nsjail（仅 Linux），不支持自定义镜像            |
| `e2b`       | 云端   | 使用 [E2B](https://e2b.dev) 云沙箱，需要 API Key |

`local` 是「自动选择」的简写，不是和 `docker`/`nsjail` 平级的第四种后端。本机容器后端（`local`/`docker`/`nsjail`）**共用** `box.local.*` 配置段；云端后端用 `box.e2b.*` 配置段。

<Note>
  `backend` 是强制值。设为 `docker` 时如果 Docker 不可用，**不会**自动回退到 Nsjail 或 E2B——只有 `local` 会自动 fan-out。

  也可以用环境变量 `BOX__BACKEND` 覆盖配置（优先级高于 `config.yaml`）。
</Note>

## 安全预设

`box.local.profile` 控制本机后端的网络、挂载、资源限制：

| Profile            | 网络     | 挂载 | 资源   | 建议场景           |
| ------------------ | ------ | -- | ---- | -------------- |
| `default`          | 关闭     | 读写 | 默认限制 | 默认选择           |
| `offline_readonly` | 关闭     | 只读 | 更严格  | 读取不可信文件        |
| `network_basic`    | 开启基础网络 | 读写 | 默认限制 | 需要访问 API 或下载依赖 |
| `network_extended` | 开启完整网络 | 读写 | 更宽松  | 开发、调试、复杂任务     |

优先使用最小权限：不需要网络就用 `default` 或 `offline_readonly`；只把必要目录加入 `allowed_mount_roots`。

## 本机后端配置（box.local.\*）

本机后端（`local` / `docker` / `nsjail`）共用以下配置：

| 配置项                         | 默认值           | 说明                                                   |
| --------------------------- | ------------- | ---------------------------------------------------- |
| `local.profile`             | `default`     | 见上文「安全预设」                                            |
| `local.image`               | 空             | Docker 后端的自定义镜像；空 = 用 profile 默认                     |
| `local.host_root`           | `./data/box`  | 主机工作目录基础路径，映射为沙箱内 `/workspace`                       |
| `local.default_workspace`   | 空             | 默认工作空间名；空 = `<host_root>/default`                    |
| `local.skills_root`         | `skills`      | Skill 包目录；相对路径解析到 `host_root` 下                      |
| `local.allowed_mount_roots` | `[host_root]` | Agent 可请求挂载的主机目录白名单                                  |
| `local.workspace_quota_mb`  | `null`        | 工作区磁盘配额（MB），`null` = 用 profile 默认                    |
| `default_memory_mb`         | `1536`        | MCP stdio 进程内存上限（MB）；可通过 `BOX__DEFAULT_MEMORY_MB` 覆盖 |

## Box 沙箱内存配置

`box.default_memory_mb` 控制每个 stdio 模式 MCP 服务进程的 nsjail cgroup 内存上限。

| 配置项                     | 说明             | 默认值  |
| ----------------------- | -------------- | ---- |
| `box.default_memory_mb` | MCP 进程内存上限（MB） | 1536 |

可通过 config.yaml 或环境变量 `BOX__DEFAULT_MEMORY_MB` 设置。

**为什么需要调整：**

* Node.js 类 MCP（npx/bunx 启动）：V8 引擎 + WebAssembly 模块初始化需要较多内存，建议 ≥ 1536 MB
* Python 类 MCP（uvx 启动）：通常 512 MB 已足够，但用默认值也没问题
* 内存不足时进程会被强制终止（return\_code=137），在日志里表现为「Box managed process exited unexpectedly」

**单个 MCP 服务覆盖：** 在 MCP 配置的 `box.memory_mb` 字段单独设置，优先级高于全局默认值。

## Docker 后端配置（box.docker.\*）

| 配置项                        | 默认值    | 说明                                                                                         |
| -------------------------- | ------ | ------------------------------------------------------------------------------------------ |
| `docker.cpu_limit_enabled` | `true` | 仅 Docker 后端生效。设为 `false` 时，Docker 沙箱容器启动时不会附带 `--cpus`；`--memory` 和 `--pids-limit` 仍会照常应用。 |

## 云端后端配置（box.e2b.\*）

设为 `backend: 'e2b'` 后配置：

| 配置项            | 默认值 | 说明                                 |
| -------------- | --- | ---------------------------------- |
| `e2b.api_key`  | 空   | E2B API Key，也可用 `E2B_API_KEY` 环境变量 |
| `e2b.api_url`  | 空   | 自建 E2B 服务地址，也可用 `E2B_API_URL`      |
| `e2b.template` | 空   | 默认 E2B 模板 ID                       |

E2B 不需要本机 Docker 或 Nsjail，每次执行都走远程沙箱。

## Docker Compose 部署

Docker Compose 部署时，沙箱配置写在 `langbot` 服务上。LangBot 启动后会通过 INIT RPC 把配置下发给 `langbot_box`。

```yaml theme={null}
services:
  langbot_box:
    image: rockchin/langbot:latest
    container_name: langbot_box
    profiles: ["box", "all"]
    volumes:
      - ${LANGBOT_BOX_ROOT:-${PWD}/data/box}:${LANGBOT_BOX_ROOT:-${PWD}/data/box}
      - /var/run/docker.sock:/var/run/docker.sock
    command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.cli.__init__", "box"]

  langbot:
    image: rockchin/langbot:latest
    volumes:
      - ./data:/app/data
    environment:
      - BOX__LOCAL__HOST_ROOT=${LANGBOT_BOX_ROOT:-${PWD}/data/box}
      - BOX__LOCAL__SKILLS_ROOT=skills
      - BOX__LOCAL__ALLOWED_MOUNT_ROOTS=${LANGBOT_BOX_ROOT:-${PWD}/data/box}
      - BOX__DOCKER__CPU_LIMIT_ENABLED=${LANGBOT_BOX_DOCKER_CPU_LIMIT_ENABLED:-true}
```

<Warning>
  `langbot_box` 需要访问 Docker daemon。只在受信任环境中挂载 `docker.sock`；并保持 Box 根目录在主机和 `langbot_box` 容器内路径一致。
</Warning>

如需 LangBot 连接外部 Box Runtime（例如远程主机），用 `box.runtime.endpoint` 指定 URL：

```yaml theme={null}
box:
  runtime:
    endpoint: 'ws://192.168.1.10:5410'
```

## 环境变量

| 环境变量                              | 写入配置                                 |
| --------------------------------- | ------------------------------------ |
| `BOX__ENABLED`                    | `box.enabled`                        |
| `BOX__BACKEND`                    | `box.backend`                        |
| `BOX__LOCAL__PROFILE`             | `box.local.profile`                  |
| `BOX__LOCAL__IMAGE`               | `box.local.image`                    |
| `BOX__LOCAL__HOST_ROOT`           | `box.local.host_root`                |
| `BOX__LOCAL__DEFAULT_WORKSPACE`   | `box.local.default_workspace`        |
| `BOX__LOCAL__SKILLS_ROOT`         | `box.local.skills_root`              |
| `BOX__LOCAL__ALLOWED_MOUNT_ROOTS` | `box.local.allowed_mount_roots`，逗号分隔 |
| `BOX__LOCAL__WORKSPACE_QUOTA_MB`  | `box.local.workspace_quota_mb`       |
| `BOX__DEFAULT_MEMORY_MB`          | `box.default_memory_mb`              |
| `BOX__DOCKER__CPU_LIMIT_ENABLED`  | `box.docker.cpu_limit_enabled`       |
| `BOX__E2B__API_KEY`               | `box.e2b.api_key`                    |
| `BOX__E2B__API_URL`               | `box.e2b.api_url`                    |
| `BOX__E2B__TEMPLATE`              | `box.e2b.template`                   |

<Note>
  不要在 `langbot_box` 服务上设置 `BOX__*` 或 `LANGBOT_BOX_*` 变量；这些变量不会被 Box Runtime 直接读取——它的配置由 LangBot 通过 INIT RPC 下发。
</Note>
