V2 Kit 仍受支持,也没有被废弃。claude 和 codex 这样的内置智能体名对应 v3 Kit,无法使用 v2 Mixin。本页介绍 v2 Kit 的用法和规范。对于新的 Kit,Docker 推荐使用 v3。V1 也仍受支持。
使用已有的 Kit
一个 v2 Kit 包含 spec.yaml(其中 schemaVersion: "2")和可选的 files/ 目录树。沙箱 Kit 定义智能体环境,Mixin 则往其中添加工具或配置。把沙箱 Kit 放在智能体名的位置,再用 --kit 添加 Mixin:
$ sbx run ./my-agent --name my-project --kit ./team-configsbx run 会把你当前的目录作为工作区。追加一个项目路径即可使用其他目录。要创建但不启动智能体,请使用 sbx create;加入一个工作区路径或 . 来挂载目录。引用可以是本地目录、ZIP 文件、OCI 制品或 Git URL。相对路径以 ./ 或 ../ 开头。对于 Docker Hub 上的 Kit,你可以省略 docker.io/,直接写 <NAMESPACE>/<KIT>:<TAG>。在 Git URL 中,ref 选择某个修订版本,dir 选择 Kit 目录。含 & 的 URL 要加引号:
$ sbx run "git+https://github.com/<ORG>/<REPOSITORY>.git#ref=<COMMIT>&dir=my-agent"git+ssh:// URL 可以配合你本地的 SSH agent 和 Git 凭据使用。 对于私有镜像仓库,请参阅 镜像仓库凭据。
用 --kit 选择 Kit 在创建时生效。要改变沙箱的 Kit 集合,需要重新创建沙箱,只有 sbx kit add支持的有限更新除外。该命令会重启沙箱,同时保留软件包、镜像、卷和智能体历史。无法从运行中的沙箱里移除 Kit。
限制 Kit 来源
来源策略请参阅限制 Kit 来源。kit.allowLocalKits 同样管辖 v2 的 ZIP 文件。
内置智能体的镜像覆盖
用 --template 可以替换内置智能体的镜像,同时保留它的配置和启动命令。替换的镜像必须支持同一个智能体。例如,与 claude 一起使用的镜像必须装有 Claude Code。
要定义带有自己启动命令和沙箱设置的环境,请参阅 v3 流程中的 构建智能体工作负载。
选择模板
Docker 以 docker/sandbox-templates:<variant> 发布智能体镜像。选择与你的智能体匹配的变体。可用的变体请参阅 基础镜像。
带 -docker 后缀的变体,例如 claude-code-docker,包含 Docker Engine,可以在沙箱内构建和运行容器。 不指定自定义模板时,内置智能体默认使用这些变体。
如果你不需要在沙箱内使用 Docker,请选择不带该后缀的变体。它占用更少资源,也不需要特权模式:
$ sbx run claude --template docker.io/docker/sandbox-templates:claude-code--template 的镜像引用中要包含镜像仓库域名。与 Kit 引用不同,模板引用不会自动补上 docker.io。
构建自定义模板
构建自定义模板需要 Docker Desktop。
在 Docker 提供的镜像基础上扩展你要运行的智能体。例如,这个 Dockerfile 给 Claude Code 镜像加上 Rust 和 protocol buffer 工具:
FROM docker/sandbox-templates:claude-code
USER root
RUN apt-get update && apt-get install -y protobuf-compiler
USER agent
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y以 root 安装系统包,然后切换回 agent,再在智能体主目录中安装工具。
构建镜像并推送到镜像仓库。把 <NAMESPACE> 换成你可以推送的 Docker Hub 命名空间:
$ docker build -t docker.io/<NAMESPACE>/my-template:v1 --push .镜像仓库凭据和加载本地构建的镜像,请参阅 加载模板。
用你的镜像运行沙箱:
$ sbx run claude --template docker.io/<NAMESPACE>/my-template:v1由于该镜像扩展自 claude-code,请与 claude 一起使用。基于 codex 的镜像则配 codex,基于 shell 的镜像配 shell,即可在不启动智能体的情况下打开 Bash。
如果你添加的工具需要网络访问,请在沙箱的网络策略中放行它们使用的域名,除非你使用 allow-all 策略:
$ sbx policy allow network "*.example.com:443,example.com:443"Kit 的种类
kind: mixin
Mixin 把能力叠加到已有沙箱上。它不能声明 sandbox: 块、extends: 或 mixins:。Mixin 可以声明 requires:,以锁定它所针对的基础智能体:
schemaVersion: "2"
kind: mixin
name: github-tools
requires:
agent: clauderequires.agent 接受一个基础智能体名。它会按 Kit 名进行校验,并在组合时强制执行。
kind: sandbox
沙箱 Kit 定义一个完整的智能体。根沙箱必须声明 sandbox: 块。使用 extends: 的沙箱可以继承父镜像,并省略自己的 sandbox: 块:
schemaVersion: "2"
kind: sandbox
name: claude-safe
extends: claudeextends: 只能用于沙箱。父项必须解析为沙箱 Kit。mixins: 同样只能用于沙箱,解析器接受它,但运行时的组合支持仍在开发中。
顶层字段
规范性的语法请参阅 v2 规范。
| 字段 | 必填 | 说明 |
|---|---|---|
schemaVersion | 是 | 规范 schema 版本。本语法使用 "2"。 |
kind | 是 | 扩展智能体的 Kit 用 mixin;定义智能体的 Kit 用 sandbox。 |
name | 是 | 唯一标识符。小写字母、数字和连字符,长度 1 到 64 个字符。 |
version | 否 | Kit 版本。 |
displayName | 否 | 便于阅读的名称。 |
description | 否 | 简短描述。 |
sourceURL | 否 | 源码仓库或文档 URL。 |
licenses | 否 | SPDX 许可证标识符。 |
locked | 否 | 子 Kit 不允许覆盖的点分路径。 |
security | 否 | 容器安全设置。security.privileged: true 会让容器以特权模式运行。 |
args | 否 | 加载 Kit 时传入的参数。仅 schema v2 支持。 |
Kit 还会声明若干行为块,例如 agentInstructions、permissions、ports、credentials、environment、setup 和 volumes。
参数
schema v2 的 Kit 可以声明参数,并在 spec.yaml 中或 files/ 下的任意位置以 ${{ kit.args.<name> }} 引用它们。替换发生在规范解码之前。
args:
version:
default: latest
description: Tool version to install
pattern: '^(latest|[0-9]+\.[0-9]+\.[0-9]+)$'
channel:
default: stable
enum: [stable, beta, nightly]
target:
required: true
description: Build target
environment:
variables:
TOOL_VERSION: "${{ kit.args.version }}"不要用 Kit 参数保存 API 令牌、密码或其他机密。请用 凭据把敏感值提供给沙箱。
| 字段 | 说明 |
|---|---|
| 参数名 | 以字母或下划线开头,只包含字母、数字、下划线和连字符。 |
default | 调用方未提供值时使用的字符串。与 required: true 互斥。 |
required | 设为 true 表示调用方必须提供值。与 default 互斥。 |
description | 可选的帮助文字,在缺少必填值时显示。 |
enum | 可选的允许值列表。与 pattern 互斥。 |
pattern | 可选的 Go RE2 正则表达式,与完整值匹配。与 enum 互斥。 |
每个参数必须声明 default(可以为空字符串默认值)或 required: true。
参数值是字符串,但替换发生在 YAML 解码之前。在字符串类型的字段中要给占位符加引号,这样像 1.20 这样的值不会被解码成数字。
向 Kit 传递参数
对每个声明了该参数的 Kit 使用 --kit-arg name=value,或加上 Kit 的 name 前缀来指定某一个 Kit。带作用域的值会覆盖共享的值:
$ sbx run ./my-agent --kit ./my-mixin --kit-arg channel=stable \
--kit-arg my-mixin.channel=beta--kit-args-file <FILE> 读取 name=value 条目,忽略空行和 # 注释。靠后的文件会覆盖靠前的文件;--kit-arg 覆盖文件中的值。命令行中重复出现的同一个键,以最后一个值为准。缺少必填值、未知参数、未声明的占位符和无效值都会在创建之前失败。必要时,把同样的标志传给 sbx kit validate 或 sbx kit inspect。参数值可能会保留在 shell 历史中,并以未加密的形式存放在参数文件里。
沙箱块
sandbox:
image: <image-ref>
build:
context: .
dockerfile: Dockerfile
args:
AGENT_VERSION: "1.0.0"
target: runtime
platforms:
- linux/amd64
entrypoint: [my-agent, "--flag"]
command:
default: ["--task-mode"]
interactive: []
resources:
cpu: 2
memory: 4g
gpu: "1"| 字段 | 必填 | 说明 |
|---|---|---|
sandbox.image | 省略 extends: 时必填 | Docker 镜像引用。 |
sandbox.build | 否 | 构建配置。运行时支持仍在开发中,因此带 build: 的 Kit 还必须设置 image:。 |
sandbox.entrypoint | 否 | 固定进程前缀,字符串数组。第一个元素是智能体二进制文件。 |
sandbox.command | 否 | 按模式区分的参数尾部。用列表简写表示 default,或用包含 default 和 interactive 的映射。 |
sandbox.resources | 否 | 可选的 CPU、内存和 GPU 约束。内存使用 4096m 或 4g 这样的字节大小字符串。 |
实际的命令在非交互式启动时是 entrypoint 加上 command.default,在 TTY 会话中是 entrypoint 加上 command.interactive。如果省略 interactive,则回退到 default。
对于使用 extends: 的 Kit,sandbox.command 会替换继承来的全部参数尾部,包括父级 sandbox.entrypoint 中二进制文件之后的标志。它不会追加到那个尾部之后。请定义子级需要的每一个参数。例如,一个在 claude 基础上添加 --settings 的子 Kit,还必须包含 --dangerously-skip-permissions 才能保留该行为。
智能体的容器镜像必须提供:
- 一个 UID 为 1000、无密码 sudo 权限的非 root
agent用户。 - 一个由
agent拥有的/home/agent/主目录。 - 在 sudo 之后依然保留的 HTTP 代理环境变量(
HTTP_PROXY、HTTPS_PROXY、NO_PROXY)。 - 智能体二进制文件,可以是内置的,也可以用
setup.install安装。
在 docker.io/sbx/shell-docker-image:latest 之上构建即可获得这些基础要求。
智能体说明
在 agentInstructions 下声明这些字段:
| 字段 | 说明 |
|---|---|
filename | AI 配置文件名。对 kind: sandbox 有意义;对 kind: mixin 会忽略并给出警告。 |
content | Markdown 说明。对沙箱来说内联到该配置文件中;对 Mixin 来说写入 Kit 记忆。 |
对 Mixin,引擎把 content 写入 <dir-of-AI-file>/kits-memory/<kit-name>.md,并在基础 AI 文件中增加一个 ## Kits 指针小节。这样每个 Mixin 的说明都留在各自的文件里。
生成的配置文件位于沙箱内已挂载工作区的上级目录。它在挂载点之外,不会取代项目中的说明文件。沙箱 Kit 内联的说明会直接进入该配置文件。
凭据
Kit 声明它需要的凭据,以及代理如何把它们注入出站请求。它不声明宿主的发现来源。用户通过密钥存储或首次运行提示提供数值,并由 凭据绑定授权使用。Kit 不能读取任意宿主环境变量或文件。
credentials 是一个列表;每个条目指明一个 service,并配置一种或多种认证机制。
| 字段 | 说明 |
|---|---|
service | 凭据标识符,与 sbx secret set 存储的值匹配。使用小写短横线格式。 |
description | 可选。批准绑定时向用户显示。 |
required | 标记该凭据对智能体不可或缺。如果没有绑定,sbx 会发出警告并在不提供该凭据的情况下启动。默认 false。 |
provider | 为提供商注册表预留。接受该字段但会给出警告,运行时没有作用。 |
apiKey | API 密钥注入(见 apiKey)。 |
oauth | OAuth 拦截(见 oauth)。 |
每个 service 必须声明 apiKey、oauth 或两者。两者在运行时都能解析时,API 密钥优先,OAuth 作为回退。
apiKey
| 字段 | 说明 |
|---|---|
name | 凭据对应的环境变量名,例如 ANTHROPIC_API_KEY。 |
proxyManaged | 为 true 时,sbx 在容器内把 name 设为 proxy-managed 哨兵值。默认 false。 |
inject[].domain | 注入凭据的域名。同时也必须在 permissions.network 中被允许。 |
inject[].header | 代理设置的 HTTP 请求头,例如 x-api-key、Authorization。 |
inject[].format | 请求头值的格式,含一个 %s 占位符,例如 "%s" 或 "Bearer %s"。与 scheme 互斥。 |
inject[].scheme | 常用认证方案的简写。bearer 展开为 Authorization: Bearer %s;basic 需要 username。与 format 互斥。 |
inject[].username | HTTP Basic 认证的用户名,例如通过 HTTPS 使用 Git 时的 x-access-token。 |
oauth
对于使用 OAuth 认证的智能体(例如 Claude Code),代理会拦截令牌响应,把真实令牌替换为哨兵值,然后在出站请求中换回真实令牌。默认情况下,令牌从不进入沙箱。设置 passthrough: true 可以不使用哨兵掩码,直接把真实的令牌响应送入沙箱。
| 字段 | 说明 |
|---|---|
tokenEndpoint.host / path | 代理拦截的 OAuth 令牌端点。 |
sentinels.accessToken / refreshToken | 写入容器、用来替代真实令牌的哨兵值。 |
credentialFile.path | 在容器内写入凭据文件的位置(~ 会展开)。 |
credentialFile.structure | 声明式 JSON 结构。支持 {{.AccessToken}}、{{.RefreshToken}}、{{.ExpiresAt}} 和 {{.Scopes}}。 |
credentialFile.template | Go 模板。支持 {{.AccessToken}}、{{.RefreshToken}}、{{.ExpiresAt}}、{{.Scopes}} 和 {{.ScopesJSON}}。 |
resourceHosts | 代理在出站请求中附加令牌的 API 主机,与令牌端点主机不同。 |
skipIfEnv | 为兼容性而接受,但在 schema v2 中被忽略。v2 绑定才是权威来源,而不是宿主环境变量。 |
responseFields | 覆盖代理从令牌响应中读取的默认字段名。 |
passthrough | 为 true 时,代理原样传递令牌响应,而不是用哨兵值替换令牌。 |
credentialFile.structure 为 credentialFile.template 提供了声明式的替代方案。引擎会把它渲染成格式正确的 JSON。如果两个字段都设置了,structure 优先。
网络
网络出站流量在 permissions.network 下声明。凭据不再携带自己的域名映射 —— 代理只会把凭据注入其 apiKey.inject 列出的域名,而沙箱访问的每个域名都必须在这里被允许。
| 字段 | 说明 |
|---|---|
permissions.network.allow | 沙箱可以访问的域名。 |
permissions.network.deny | 沙箱被禁止访问的域名。拒绝规则优先于允许规则,在组合的 Kit 之间同样如此。 |
允许和拒绝的模式:
| 模式 | 示例 | 状态 |
|---|---|---|
| 精确主机 | api.example.com | 已强制执行 |
| 精确主机和端口 | api.example.com:8080 | 已强制执行 |
| 单标签通配符 | *.example.com | 已强制执行 |
| 多标签通配符 | **.example.com | 已解析;尚未强制执行 |
| 端口范围 | api.example.com:80-443 | 已解析;尚未强制执行 |
| 端口通配符 | api.example.com:* | 已解析;尚未强制执行 |
| CIDR | 10.0.0.0/8 | 已解析;尚未强制执行 |
在 v1 中这是 network: 块(allowedDomains / deniedDomains,以及 serviceDomains / serviceAuth)。在 v2 中,这些字段会导致解码错误。
端口
把 ports 声明为一个条目列表,用于把沙箱服务暴露给宿主:
| 字段 | 说明 |
|---|---|
container | 容器端口,1 到 65535。 |
protocol | tcp 或 udp。留空表示只发布一种协议族,详见下文。 |
name | 可选标签,供列出已发布端口绑定的工具使用。 |
宿主端口是临时分配的。除非服务监听 IPv6,否则请让 protocol 保持为空:空值只发布 IPv4(127.0.0.1),这正是绑定在 0.0.0.0 上的服务所需要的;而 tcp 会同时发布 127.0.0.1 和 ::1 —— 通过 ::1 到达的客户端会被接受,随后被重置,如果沙箱内没有服务在监听该地址。用户可以用 sbx ports --publish <host>:<container> 固定宿主端口。
环境
| 字段 | 说明 |
|---|---|
environment.variables | 直接在容器中设置的键值对。 |
不要设置 DASH_、SBX_ 或 DOCKER_ 开头的变量,并避免覆盖 HOME、USER、SHELL、PATH、LD_PRELOAD 和 LD_LIBRARY_PATH。运行时保留这些名称,可能会覆盖它们。
安装
setup.install、setup.startup 和 setup.files 是命令或文件的列表,其字段见下文。
执行顺序
创建沙箱时,Kit 内容按以下顺序应用:
- 网络权限和环境变量。
files/home/下的静态文件。setup.install命令,按声明顺序执行。setup.files条目。setup.startup命令,为每次沙箱启动注册。files/workspace/下的静态文件,在工作区就绪之后。带--clone时,这一步在仓库克隆完成之后。
对于堆叠的 Kit,每个阶段的条目按 --kit 的顺序应用。install 命令可以使用 files/home/ 中的捆绑文件,但不能使用 files/workspace/ 或 setup.files 中的文件,因为那些文件更晚才落地。
sbx kit add 会重新创建沙箱,而不是就地修改它。它支持的 Mixin Kit 仅限于 environment.variables、setup.install、setup.startup 和 permissions.network.allow,其顺序与创建沙箱时相同。启动命令在 Kit 被添加之后以及之后每次沙箱启动时运行。该命令会拒绝声明了静态文件或 setup.files 的 Kit。要使用这些字段,请在创建沙箱时一并包含该 Kit。
install
在应用 Kit 时同步运行,无论是在创建沙箱期间还是通过 sbx kit add。Shell 字符串会传给 sh -c。
Kit 的 install 命令从模板镜像配置的 WORKDIR 开始。Docker 提供的模板使用 /home/agent/workspace,在直接挂载或克隆模式的沙箱中它不一定是主工作区。不要依赖当前目录来定位工作区文件。对来自 files/home/ 的捆绑资源,请使用绝对路径。
| 字段 | 默认值 | 说明 |
|---|---|---|
command | — | Shell 命令字符串。 |
user | "0" | 以哪个用户运行。"0" 表示 root。 |
description | — | 便于阅读的描述。 |
startup
在每次沙箱启动时运行。字符串数组,不经过 shell 解释。数组中的 $WORKSPACE_DIR 引用会原样传递。要展开它,请通过 shell 运行该命令,例如 ["sh", "-c", "..."]。
| 字段 | 默认值 | 说明 |
|---|---|---|
command | — | 命令及其参数,字符串数组。 |
user | "1000" | 以哪个用户运行。"1000" 表示智能体。 |
background | false | 在这条命令结束前阻塞后续的启动命令。设为 true 则让后续命令无需等待即可运行。 |
description | — | 便于阅读的描述。 |
启动命令是非交互式的。它们在智能体接入之前运行,没有连接终端,因此无法向用户提问(例如交互式的 aws login 会挂起或失败)。它们也不会阻塞智能体的 entrypoint:启动命令一旦分发出去,智能体就会启动,与 background 无关。值为 false 是在启动分发器内部等待当前命令结束后再运行下一条命令;它不会延迟智能体的 entrypoint。把启动命令用于可以与智能体并行进行的工作。任何需要在智能体运行前落到磁盘上的值,请用 setup.files。
启动命令必须满足幂等。它们在每次沙箱启动时运行,并在容器重启时重放,因此一条第二次调用就失败或行为异常的命令会破坏重启路径。用存在性检查加以保护,用更新插入代替单纯插入,并优先选择无论运行多少次都收敛到相同最终状态的命令。
files
在沙箱启动时写入的文件,支持运行时替换。
| 字段 | 默认值 | 说明 |
|---|---|---|
path | — | 容器内的绝对路径。 |
content | — | 文件内容。写 ${WORKDIR} 表示工作区路径。 |
mode | "0644" | 八进制的文件权限。 |
onlyIfMissing | false | 文件已存在时跳过。 |
运行时以 UID 1000 的智能体用户身份写入这些文件。目标路径必须对该用户可写。要写入 /etc 这类由 root 拥有的路径,请使用 install 命令,它默认以 root 身份运行。如果智能体之后需要修改该文件,请在 install 命令中设置属主。
在 content 中写 ${WORKDIR},在命令中写 $WORKSPACE_DIR。三个名字看起来相近,含义却不同:
| 名称 | 是什么 | 适用范围 |
|---|---|---|
${WORKDIR} | 工作区路径的占位符 | 仅 setup.files[].content |
WORKSPACE_DIR | 运行时设置的工作区路径环境变量 | Shell 命令,以及智能体 |
WORKDIR | 模板镜像 Dockerfile 中的工作目录 | 命令的起始位置,见 install |
运行时在创建沙箱时替换 ${WORKDIR},且只在 content 内部替换,绝不会出现在 path 或命令中。WORKSPACE_DIR 是环境变量,因此 $WORKSPACE_DIR 引用只有在 shell 运行该命令时才会展开。install 字符串会通过 sh -c 运行。startup 数组在没有 shell 的情况下运行。Dockerfile 的 WORKDIR 并不定义环境变量。
Shell 初始化和服务日志
使用 Docker 模板时,在 install 命令中把 shell 初始化追加到 /etc/sandbox-persistent.sh。保留已有内容,并且不要加入补全脚本:交互式和非交互式的 Bash 命令都会读取这个文件。对于后台服务,把启动输出重定向到文件,再用 sbx exec 读取。使用 background: true,而不是在末尾加 &。
静态文件
my-kit/files/
├── home/ → /home/agent/
└── workspace/ → primary workspace path| Kit 路径 | 容器目标位置 |
|---|---|
files/home/ | /home/agent/(配置文件、点文件) |
files/workspace/ | 主工作区路径 |
上级目录会自动创建。已存在的文件会被覆盖。绝对路径和路径穿越序列(../../)会被拒绝。
静态文件可以提供 linter 设置、辅助脚本或智能体技能。例如,一个 Claude Code 项目技能应放在 files/workspace/.claude/skills/<NAME>/SKILL.md。
卷
把 volumes 声明为一个挂载列表,包含这些字段:
| 字段 | 说明 |
|---|---|
path | 必填,容器内的绝对路径。 |
type | 留空表示块存储卷,或 tmpfs 表示内存支持的存储。 |
size | 可选的字节大小字符串。 |
mode | 可选的八进制权限。 |
卷只在创建沙箱时应用。sbx kit add 无法把卷挂载到运行中的容器。
派生已有的智能体
这个例子需要一个带内置 v2 智能体的较旧 sbx 版本。使用最新的 sbx 创建沙箱时,内置名称对应的是 v3 Kit。要做 v3 定制,请参阅 编写 Kit 集合。
沙箱 Kit(kind: sandbox)从头定义一个完整的智能体。最常见的变体是从内置智能体派生。用 extends: 继承父级的完整配置,只声明你想改动的字段。这个例子替换了内置的 claude entrypoint,让 Claude Code 使用手动权限模式,而不是跳过审批提示:
schemaVersion: "2"
kind: sandbox
name: claude-safe
displayName: Claude Code (with approval prompts)
description: Claude Code in manual permission mode
extends: claude
sandbox:
entrypoint: [claude, "--permission-mode", "manual"]子级会继承内置镜像、凭据、网络权限、持久化卷、设置、MCP 集成、智能体说明、安装条目和环境变量。它的 sandbox.entrypoint 会替换继承来的 entrypoint。
启动时,在内置智能体名的位置传入沙箱 Kit:
$ sbx run ./claude-safe安装内部 CA 证书
把每张 PEM 编码的根证书放在 files/home/ 下,扩展名为 .crt。对于 files/home/internal-ca.crt,使用:
schemaVersion: "2"
kind: mixin
name: internal-ca
setup:
install:
- command: "install -m 0644 /home/agent/internal-ca.crt /usr/local/share/ca-certificates/internal-ca.crt && update-ca-certificates"
user: "0"这会更新系统信任库。有多个 CA 时,请在运行 update-ca-certificates 之前安装全部证书。
由沙箱管理的智能体配置
内置智能体 Kit 为沙箱安装预留了以下路径。即便某个文件只针对某个功能才需要,也要把这些路径视为沙箱管理。不要用静态文件、setup.files 或 install 命令针对它们。后续的安装步骤可能会替换你的内容,或依赖被你的文件移除的设置。在这张表中,~ 表示 /home/agent。
| 内置智能体 Kit | 受管理的配置路径 |
|---|---|
claude | ~/.claude.json、~/.claude/settings.json、~/.claude/.config.json |
codex | ~/.codex/config.toml |
copilot | ~/.copilot/config.json |
cursor | ~/.cursor/cli-config.json |
devin | ~/.config/devin/config.json、~/.config/devin/mcp_config.json |
kiro | ~/.kiro/settings/mcp.json |
opencode | ~/.config/opencode/opencode.json |
在支持的情况下请使用独立的设置文件:Claude Code 接受 --settings,OpenCode 读取 OPENCODE_CONFIG。不要用 setup.startup 保存智能体必须在初始化期间读取的设置;启动命令不会阻塞 entrypoint。
校验并检查 Kit
用下面这些命令在分享之前检查一个 Kit:
sbx kit validate <path>—— 检查 Kit 目录或 ZIP 的格式是否正确。sbx kit inspect <path>—— 显示 Kit 的详情。加上--json可获得机器可读的输出。
加上 --offline 可以不启动守护进程、不登录,就地校验或检查一个本地目录或 ZIP。离线检查会跳过 Kit 来源和签名策略;它们并不能说明该 Kit 是否被允许加载。
打包与分发
sbx kit pack <path> -o <file.zip>—— 把目录打包成 ZIP 文件以便分享。sbx kit push <path> <ref>—— 发布到 OCI 镜像仓库(例如ghcr.io/myorg/my-kit:1.0)。sbx kit pull <ref>—— 把 Kit 下载到当前目录,schema v1 为.zip,schema v2 为.tar.gz。用--output <FILE>指定输出路径。
对于 Docker Hub,sbx kit pull 和 sbx kit push 使用 sbx login 的会话。对于其他镜像仓库,它们优先使用通过 sbx secret set --registry存储的凭据。 两条命令都会回退到 Docker 凭据存储,因此 docker login 得到的凭据同样可用。
签名并验证 Kit
使用兼容 cosign 的 Sigstore 签名来验证是谁批准了一个 Kit,以及它被签名的内容是否未被改动。默认采用无密钥签名。用证书身份和 OpenID Connect(OIDC)签发者验证无密钥签名:
$ sbx kit sign ./my-kit/
$ sbx kit verify \
--certificate-identity user@example.com \
--certificate-oidc-issuer https://accounts.google.com \
./my-kit/对于基于密钥的签名,请使用 ECDSA P-256 密钥对:
$ sbx kit sign --key cosign.key ./my-kit/
$ sbx kit verify --key cosign.pub ./my-kit/对于本地目录,sbx kit sign 会在 spec.yaml 旁边写入一个 kit.sig.bundle 文件。请提交这个文件,这样使用者就能验证从 Git 仓库加载的 Kit。
Git 的行尾转换和 clean filter 可能让源码签名失效。如果 sbx kit sign 警告存在这类转换,请确保 Git 在分享 Git 引用之前原样保留被签名的文件。
对于 OCI Kit,签名以 OCI referrer 的形式保存。你可以在推送之后签名,也可以一步完成推送和签名:
$ sbx kit push ./my-kit/ ghcr.io/myorg/my-kit:1.0 --signZIP Kit 无法携带可验证的签名。
查看来源证明
推送一个 Kit 时还会附带一份来源证明(provenance)attestation,记录它的内容 digest、声明的沙箱镜像,以及从工作树推送时的源码 Git 提交。检查它可以确认已发布 Kit 的来源:
$ sbx kit provenance ghcr.io/myorg/my-kit:1.0来源证明默认不带签名。发布时使用 sbx kit push --sign,可以为 Kit 清单和它的来源证明同时签名。
要求 Kit 必须签名
在要求签名之前,先把 kit.trustedSigners 设为你信任的身份或密钥。否则,sbx 会使用默认策略,即信任由 Google 的 OpenID Connect 签发者出具的 Docker 员工身份。无密钥策略必须同时指定证书身份及其 OpenID Connect 签发者:
$ sbx settings set kit.trustedSigners \
'[{"identity":"release-bot@example.com","issuer":"https://accounts.google.com"}]'
$ sbx settings set kit.requireSignature true要信任基于密钥的签名,把策略设为公钥路径:
$ sbx settings set kit.trustedSigners '[{"key":"/path/to/cosign.pub"}]'
$ sbx settings set kit.requireSignature true当 kit.requireSignature 为 true 时,sbx 会拒绝未签名的 Kit、与 kit.trustedSigners 不匹配的签名,以及 ZIP Kit。该策略在从本地目录、Git 仓库或 OCI 镜像仓库加载 Kit 时都生效。
签名覆盖 spec.yaml 和 Kit 的 files/ 内容,但不覆盖镜像标签这类可变的依赖,也不覆盖 install 和 startup 命令下载的内容。当这些依赖必须保持不可变时,请用 digest 或校验和来锁定它们。
Schema 版本
Schema v2 从 Docker Sandboxes 0.36 版本起开始支持。本页的语法使用 schemaVersion: "2"。版本 "1" 也仍然接受。V3 是另一种格式,用于完全由 v3 工作负载和 Mixin 构建的环境。V3 Kit 不能与 v1 或 v2 Kit 组合。该流程请参阅 Kits v3。
迁移到 schemaVersion: "2" 时,把 v1 字段替换为对应的 v2 字段:
| v1 | v2 |
|---|---|
credentials.sources.<id> | 带 service 的 credentials: 列表条目 |
network.allowedDomains / deniedDomains | permissions.network.allow / deny |
network.serviceDomains / serviceAuth | credentials[].apiKey.inject |
network.publishedPorts / publishedPorts | 顶层的 ports |
独立的 oauth: 块 | credentials[].oauth |
oauth.skipIfEnv | 接受但被忽略 |
environment.proxyManaged | credentials[].apiKey.proxyManaged |
memory / agentContext | agentInstructions.content |
kind: agent / agent: 块 | kind: sandbox / sandbox: 块 |
sandbox.aiFilename | agentInstructions.filename |
sandbox.entrypoint.run | sandbox.entrypoint |
sandbox.entrypoint.args | sandbox.command.default |
sandbox.entrypoint.ttyArgs | sandbox.command.interactive |
tmpfs: | type: tmpfs 的 volumes: 条目 |
volumes:(映射形式) | volumes: 序列(- path: <path>) |
commands: / commands.initFiles | setup: / setup.files |
settings: / kitDir / persistence | 已移除 |
在 v2 中,凭据发现也移出了 Kit:Kit 声明自己需要哪些凭据以及如何注入,但每个值来自哪里由用户通过 凭据绑定控制。
NOTE
mixins 和 sandbox.build 解析器可以接受,但运行时支持仍在开发中。 设置了 sandbox.build 的 Kit 还必须设置 sandbox.image。
把环境迁移到 v3
选择一个 v3 工作负载,转换或替换它的 Mixin,然后创建一个独立的沙箱。每个被选中的 Kit 都必须使用 v3。运行已有的沙箱会保留它记录的 Kit 配置。
对于环境文件,请参阅添加 v3 Kit。 保持它的 schemaVersion: "1":环境文件的版本与 Kit 描述符版本无关。
仅修改 schemaVersion 并不会转换一个 Kit。请把可复用的镜像内容与沙箱初始化分开,并声明运行时能力:
| V2 的写法 | V3 的对应写法 |
|---|---|
kind: sandbox | 带 Dockerfile 配方的 kind: workload |
sandbox.image | Dockerfile 的 FROM |
sandbox.entrypoint、sandbox.command、environment.variables | Dockerfile 的 ENTRYPOINT、CMD 和 ENV |
extends | 用于组合的 Mixin,或带自己描述符的派生工作负载镜像 |
setup.install | 用于可复用内容的 Dockerfile RUN;用于沙箱初始化的生命周期 install |
setup.startup 和 setup.files | 生命周期能力的 startup 和 files |
setup.files[].onlyIfMissing: true | 生命周期的 files[].overwrite: false |
自动注入 files/home/ 和 files/workspace/ | Dockerfile COPY,目标路径由运行时挂载提供时使用生命周期钩子 |
permissions.network 和 credentials | 网络策略能力和凭据能力 |
agentInstructions | Agent context 能力 |
setup.files[].content 中的 ${WORKDIR} | 生命周期 files 内容中的 ${{ kit.env.WORKSPACE_DIR }} |
转换运行时安装步骤和能力声明时,请遵循 v3 编写指南。 用 Kit 集合把已发布的 v3 组件与你的设置组合起来。要从基础镜像重新构建智能体环境,请参阅 构建智能体工作负载。