关于 offload-to-sandbox
offload-to-sandbox 是一项技能,可将繁重构建和长时间测试从本机转移到 Vercel Sandbox Linux 微型虚拟机。它指导开发者和 Agent 准备快照、运行隔离任务环境、传输文件并管理任务生命周期。
主要功能
- 01创建可复用的基础快照
- 02为每项任务启动独立沙箱
- 03传输源文件与结果文件
- 04执行并监控远程命令
- 05管理超时与资源清理
适用场景
- 01在远程 Linux 环境运行大型构建
- 02将长测试套件拆分到多个沙箱
- 03为并行 Agent 提供隔离环境
- 04避免反复安装依赖
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ vercel/ vercel-plugin --skill offload-to-sandbox安装后在 Claude Code 中输入/offload-to-sandbox确认已加载。
详细介绍
将工作卸载到 Vercel Sandbox
Vercel Sandbox 是一种 Linux 微型虚拟机(x86_64),可在几秒内创建,并在完成后删除。因此,它很适合充当远程工作节点:让繁重的构建和耗时的测试套件不占用你的笔记本电脑,并为每个 Agent 或任务提供一台干净的机器。本技能介绍如何使用 vercel sandbox CLI 高效完成这些工作。有关 @vercel/sandbox SDK 和运行不可信代码,请参阅 vercel-sandbox 技能。
何时卸载,哪些工作留在本地
卸载:
- 完整的测试套件,尤其是可拆分并行运行的套件。
- 耗时数分钟或需要 Linux 的构建。
- 同时执行多个任务:每个任务或每个 Agent 使用一个 Sandbox。
- 任何会占满本地磁盘的工作(大型构建目录、多个 worktree)。
留在本地:
- 编辑、
git、小型定向测试、类型检查、lint 和任务编排。 - 任何需要 Sandbox 不具备的本地凭据或硬件的工作。
多个 Agent 共用一台机器时,一个不错的默认做法是:Agent 在本地编辑并运行快速的定向检查,把所有繁重工作交给各自的 Sandbox。
计划限制
| Hobby | Pro | Enterprise | |
|---|---|---|---|
| 最大 vCPU 数(每个 vCPU 配备 2 GB 内存) | 4(8 GB) | 8(16 GB) | 32(64 GB) |
| 最长会话时长 | 45 分钟 | 24 小时 | 24 小时 |
| 并发 Sandbox 数 | 10 | 10,000 | 10,000 |
--vcpus 可设为 1,或不超过计划上限的偶数;默认值为 2。以下示例使用 Pro 规格(--vcpus 8、--timeout 3h)。在 Hobby 计划下,请使用 --vcpus 4,并将超时设为 45m 或更短。Hobby 计划每月还仅包含 5 小时的活跃 CPU 时间,因此,实际上要进行繁重的工作卸载需要 Pro 计划。
运行中的 Sandbox 按活跃 CPU 时间和已配置内存计费。快照则按每 GB 每月收取快照存储费用,且只要快照存在就会持续计费。
只需准备一次基础快照
在每个新 Sandbox 中安装工具链和依赖会浪费时间和金钱。只需准备一次并创建快照,之后从该快照启动其他所有 Sandbox:
# 1. Create a builder sandbox from the default image (Ubuntu, Node.js, Python, common tools).
vercel sandbox create --name base-builder --non-persistent --vcpus 8 --timeout 2h --image vercel/sandbox/universal
# 2. Install the pinned toolchain and build the baseline tree once.
vercel sandbox copy ./setup-base.sh base-builder:/vercel/sandbox/setup-base.sh
vercel sandbox exec base-builder -- sh -c 'cd /vercel/sandbox && sh setup-base.sh; echo "exit=$?"'
# 3. Snapshot it (this stops the sandbox). The ID is printed on stderr, not stdout.
vercel sandbox snapshot base-builder --stop --expiration 0 2>&1 | grep -o 'snap_[A-Za-z0-9_-]*' | head -n 1 > BASE_SNAPSHOT
test -s BASE_SNAPSHOT
# 4. The builder is no longer needed. Removing it keeps the snapshot.
vercel sandbox remove base-builder
创建快照前,请确认第 2 步输出了 exit=0(有关原因,请参阅运行命令)。
基础环境中应包含:
- 项目固定使用的确切工具链版本(编译器、运行时、包管理器)。
- 主分支在已知提交上的已安装并构建版本,作为只读基线(例如
/vercel/sandbox/base)。 - 任务会重复使用的小型辅助脚本(例如
prepare.sh,用于将刚推送的代码树转换为可运行的检出目录)。
将快照 ID 保存在工具所在目录中的文件里。--expiration 0 表示快照永不过期,因此会一直计费,直到你将其删除。工具链变更时,请创建新快照,并使用 vercel sandbox snapshots delete <old-id> 删除旧快照。大型运行开始前,请检查 vercel sandbox snapshots get "$(cat BASE_SNAPSHOT)" 是否仍显示状态为 created;已删除或已过期的快照会显示 deleted。
每个任务创建一个 Sandbox
vercel sandbox create --name exp-parser --non-persistent --snapshot "$(cat BASE_SNAPSHOT)" \
--vcpus 8 --timeout 3h --tag app=my-project --tag owner=agent-parser --silent
- 按所有者和用途命名(
exp-parser、exp-parser-2),避免并行工作的 Agent 发生冲突。名称在每个项目中都是唯一的,且在 Sandbox 被移除前会一直占用。绝不要使用其他 Agent 的 Sandbox。 - **规格:**每个 vCPU 配备 2 GB 内存,这是增加内存的唯一方式。占用内存较多的步骤(大型编译、大型链接任务)可能会被 Linux OOM killer 终止。若未达到计划的 vCPU 上限,请提高规格;达到上限时,请降低步骤的并行度(例如减少构建任务数),或单独运行该步骤。
- 标签(每个 Sandbox 最多 5 个)有助于清理:结束时,按所有者标签列出并移除所有 Sandbox。
生命周期和清理
沙盒默认会持久保留:会话停止时,文件系统会生成快照,以便之后恢复沙盒,而该快照会按快照存储计费。任务沙盒不需要这样做,因此这里每次调用 create 都会传入 --non-persistent。
--timeout设置的是会话时长,而不是沙盒的生命周期。默认值为 5 分钟。超时后,会话会停止,其中运行的所有进程都会被终止,包括已分离的作业。此时,非持久化沙盒会丢失整个文件系统。请根据整个任务设置超时时长。之后可以用vercel sandbox config timeout <name> <duration>修改;提高超时时长也会延长当前运行的会话。- 任务完成后,运行
vercel sandbox remove <name>。vercel sandbox stop只会结束当前会话:沙盒仍会保留其名称,持久化沙盒的快照也会继续计费。Vercel 会在 14 天不活动后移除无法恢复的沙盒,因此除非手动移除,否则已停止的非持久化沙盒会一直占用其名称。 - 移除沙盒不会删除快照,因此基础快照会在任务清理后保留。对
remove使用--delete-orphan-snapshots,还会删除该沙盒独有、未被其他沙盒使用的快照。移除创建基础快照的构建沙盒时,不要传入此参数。 - 清理崩溃的 Agent 遗留的孤立沙盒,使用
vercel sandbox list --all --tag owner=<agent>。--all会包含已停止的沙盒(默认只显示运行中的沙盒),而list一次只能按一个标签筛选。使用vercel sandbox remove <name>...移除列出的所有沙盒。只有在没有 Agent 仍在工作时,才使用--tag app=my-project清理整个项目。
移入代码而不重新安装依赖项
发送源代码,而不是构建产物。将 Git 已知的文件(已跟踪文件,以及未忽略的未跟踪文件)打包为一个 tarball,复制并解压到旧目录旁边。然后将旧目录中的大型目录(node_modules)移到新目录中,无需重新安装,最后交换这两个目录。包装脚本中的 sbx push 正是这样做的:
sbx push exp-parser . /vercel/sandbox/cand
- 每次更改后都推送;这只需几秒钟。然后运行幂等的准备步骤,只安装或重建发生变化的内容(例如,仅在锁文件发生变化时安装依赖项)。
- 在沙盒内构建特定于平台的产物。不要将 macOS 二进制文件复制到 Linux 虚拟机中。
- 不要推送
.git或依赖目录。如果需要在远程环境中保留 Git 历史记录,请推送 bundle,或在沙盒内运行git clone。 - 删除已跟踪文件但未暂存,会导致
tar失败。请先暂存删除操作(git rm)。
直接读取、写入和复制文件
独立的 sandbox CLI 在包含 vercel/sandbox#380 的版本中支持文件命令。使用 npm i -g sandbox 安装或更新,然后在使用以下示例前检查已安装的命令:
sandbox --version
sandbox read --help
sandbox write --help
sandbox copy --help
确认存在 read 和 write,并且 copy --help 列出了 --recursive。如果这些命令不可用,请继续使用 vercel sandbox copy 和下方的 sbx 封装命令。Vercel CLI 自带的 Sandbox CLI 版本独立于此,因此 sandbox 支持这些功能并不代表 vercel sandbox 也支持。
使用与现有任务沙箱相同的团队和项目。按照身份验证与作用域中的说明设置 SBX_SCOPE 和 SBX_PROJECT;独立 CLI 也必须完成身份验证。
name=exp-parser
: "${SBX_SCOPE:?set SBX_SCOPE to your team slug}"
: "${SBX_PROJECT:?set SBX_PROJECT to your project name}"
# Read a sandbox file to stdout without changing its bytes.
sandbox read --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "${name}:/vercel/sandbox/cand/package.json"
# Write a script from stdin and make it executable.
sandbox write --scope "$SBX_SCOPE" --project "$SBX_PROJECT" --mode 755 "${name}:/vercel/sandbox/check.sh" <<'SCRIPT'
#!/bin/sh
cd /vercel/sandbox/cand
npm test
SCRIPT
# Copy a prepared local directory into the sandbox.
sandbox copy -r --scope "$SBX_SCOPE" --project "$SBX_PROJECT" ./task-input "${name}:/vercel/sandbox/task-input"
# Download the result directory after the task has produced it.
sandbox copy -r --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "${name}:/vercel/sandbox/results" ./results
read(也可用 cat)会将文件内容输出到 stdout。write 会用 stdin 替换目标文件;如果本地已有文件,可使用 < ./script.sh 重定向。两者在失败时都会返回非零状态。
递归复制会将源目录的内容放入目标目录,并保留空目录、符号链接和权限。Windows 下载会拒绝文件名中含有反斜杠或冒号的文件。复制操作会复制所有条目,包括被忽略的文件,并保留目标目录中无关的文件。可将其用于准备好的输入目录和结果。对于需要基于 Git 进行筛选、删除过期文件并复用远程 node_modules 的项目更新,请继续使用 sbx push。
运行命令
vercel sandbox exec --timeout 2h exp-parser -- sh -c 'cd /vercel/sandbox/cand && npm test -- --shard 1/4; echo "exit=$?"'
- 将整条命令作为一个单引号字符串传给
sh -c。否则,本地 shell 会在沙箱看到命令前展开$VARS和 glob。尤其是 zsh 会对未匹配的 glob 报错,并将$var:r、$var:h等视为修饰符;请使用${var}。 - 检查自带 CLI 的退出行为。 在
vercel64.5.0(Sandbox CLI 4.4.0)中,即使远程命令失败,vercel sandbox exec也会以 0 退出。在该版本中,请以echo "exit=$?"结束远程命令并读取输出,或者使用会返回远程状态的sbx exec。独立的 Sandbox CLI(先运行npm i -g sandbox,再运行sandbox exec ...)会传递远程退出代码。 - 对于超过一行的命令,请在本地编写脚本,通过
vercel sandbox copy将其复制进去,然后运行。这样更容易处理引号、检查和重新运行。 exec --timeout是可选参数,没有默认值。超时后,命令会收到 SIGKILL 并被终止,CLI 会输出Command was killed (SIGKILL, exit code 137)。不设置该参数时,命令会一直运行,直到完成或会话超时。- 如果要比较耗时,请在同一个沙箱中运行两个版本,因为同等规格的主机速度也可能不同。
使用独立 CLI 运行长时间任务
如果已安装的 CLI 支持原生命令管理,请使用该功能。安装独立 CLI 并按照上述说明完成身份验证后,检查:
sandbox --version
sandbox exec --help
sandbox commands --help
确认 exec 列出了 --detach 和 --stdin,并且 commands 列出了 get、logs、wait 和 kill。请将这些检查与上面的文件命令检查分开进行:CLI 版本可能先支持命令管理,之后才支持 read、write 和递归复制。Vercel CLI 自带的 Sandbox CLI 版本独立于此。
在现有沙箱中启动任务并保存其命令 ID:
name=exp-parser
: "${SBX_SCOPE:?set SBX_SCOPE to your team slug}"
: "${SBX_PROJECT:?set SBX_PROJECT to your project name}"
command_id=$(sandbox exec --scope "$SBX_SCOPE" --project "$SBX_PROJECT" --detach "$name" -- sh -c 'cd /vercel/sandbox/cand && npm run test:all')
printf '%s\n' "$command_id"
sandbox commands get --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$name" "$command_id"
sandbox commands logs --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$name" "$command_id"
sandbox commands wait --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$name" "$command_id"
get 会检查状态,但不会等待。logs 会持续输出 stdout 和 stderr,直到命令退出;如果想查看任务运行情况,请使用它。wait 会返回远程退出状态,可据此判断任务是否成功。从另一个终端返回该任务时,请保留沙箱名称和命令 ID。
若要取消仍在运行的任务,请使用保存的命令 ID:
sandbox commands kill --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$name" "$command_id" --signal SIGTERM
sandbox commands wait --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$name" "$command_id"
取消操作通常会产生非零退出状态。终止命令不会停止沙箱。命令 ID 仅在当前会话中有效;请在会话停止前收集结果。分离运行的命令仍会在命令超时或沙箱会话超时时结束。
在没有交互式终端的情况下通过管道传入输入
对于读取输入后便结束的命令,请使用 --stdin:
printf 'hello\n' | sandbox exec --scope "$SBX_SCOPE" --project "$SBX_PROJECT" --stdin "$name" -- cat
这会打印 hello。CLI 会转发输入,并在本地输入结束时关闭远程 stdin。管道和脚本请使用 --stdin;它不能与 --interactive 一起使用。对于分离式输入,exec --detach --stdin 会保持 stdin 打开,供后续的 commands write 调用使用;在等待需要输入结束信号的程序之前,请使用 commands close-stdin 结束输入。每次写入完成后,再开始下一次写入。请将命令日志视为文本;二进制文件请使用文件传输。
回退到较旧版本的 CLI
如果无法使用原生命令管理功能,请使用现有的 sbx exec 包装器处理退出状态。对于长时间运行的任务,请使用下方的状态文件方案。沙箱会话超时时间必须覆盖整个任务:
vercel sandbox exec exp-parser -- sh -c 'cd /vercel/sandbox/cand && rm -f /tmp/test.status && nohup sh -c "npm run test:all > /tmp/test.log 2>&1; echo \$? > /tmp/test.status" > /dev/null 2>&1 &'
# later, cheap polls:
vercel sandbox exec --timeout 30s exp-parser -- sh -c 'cat /tmp/test.status 2>/dev/null || tail -3 /tmp/test.log'
获取结果
- 让远程端写入精简的结果文件(失败测试名称摘要、退出代码、JSON 报告),然后只复制这些文件回来:
vercel sandbox copy exp-parser:/tmp/results.json ./results/results.json。此处介绍的捆绑 CLI 每次copy调用只能移动一个文件,且需要指定完整的目标文件路径。若要复制整个结果目录,请在可用时使用独立的递归复制功能。 - 在那个较旧的捆绑 CLI 中,源文件不存在时,
copy会打印错误但不会失败,因此请在之后检查本地文件是否存在(sbx get会进行检查)。 - 在远程端压缩大型日志,仅在需要时再获取。通过
exec流式传输数兆字节的输出速度很慢,而且 Agent 读取时会浪费上下文。
分片并行
- 使用测试运行器的分片功能或一个编排脚本,按分片索引将耗时的测试套件拆分到 N 个沙箱中,并同时运行这些分片。
- 为每项任务分配独立的沙箱。十个 Agent 各自在自己的沙箱中工作,胜过十项任务排队等待一台机器。
- 根据预算限制并发,而不是根据 API 允许的上限。每个运行中的沙箱都会产生费用。
- 大规模扇出受 vCPU 分配速度限制。空闲的 Pro 团队每分钟起始可分配 150 个 vCPU(18 个各配备 8 个 vCPU 的沙箱),并会随着持续使用而提升;Hobby 每分钟允许 20 到 40 个。
区分既有故障与新故障
远程测试套件通常会有一些与代码更改无关的故障:环境差异、易出错的测试,以及主分支上已有的故障。
- 在同一沙箱中,对未修改的基线代码树重新运行失败的测试。基线中没有的故障才是由你的更改引起的。
- 在工具旁维护一份简短的已知环境故障清单,避免其他人重复排查。
- 迭代时运行针对性检查。在最终候选版本上运行完整测试套件,不要在每个中间步骤都运行。
身份验证与作用域
- 令牌:
vercel sandbox依次使用--token、VERCEL_AUTH_TOKEN、VERCEL_TOKEN,然后使用你的vercel login会话。仅当这些都不可用时,才会回退使用VERCEL_OIDC_TOKEN环境变量。对于 CI 或长时间运行的自动化,请设置VERCEL_TOKEN。 - 独立的
sandboxCLI 会读取VERCEL_AUTH_TOKEN,但不会读取VERCEL_TOKEN;它还会从当前目录加载.env文件。因此,从.env.local读取的VERCEL_OIDC_TOKEN会优先于你在该目录中的登录会话,其项目也会成为默认作用域。 - 团队和项目: 沙箱及其名称均属于一个项目。
--scope(或--team)和--project用于设置项目。未指定时,如果令牌是 OIDC 令牌,CLI 会先使用令牌中的项目;然后使用当前目录中的.vercel/project.json(由vercel link创建);最后使用你的默认团队和名为vercel-sandbox-default-project的项目(如有需要会创建该项目)。 - 在脚本中明确传入
--scope和--project。否则,脚本从其他目录运行时会使用不同的项目,无法查看、复用或清理你的沙箱。
用一个小脚本封装
轻量封装可避免大多数错误,并让 Agent 指令保持简短。将以下内容保存为 sbx,赋予其可执行权限,并设置 SBX_SCOPE、SBX_PROJECT 和 SBX_OWNER(在 Hobby 上还要设置 SBX_VCPUS=4 SBX_TIMEOUT=45m):
#!/bin/sh
# sbx: offload work to Vercel Sandboxes through `vercel sandbox`.
# sbx create <name> new task sandbox from the base snapshot
# sbx push <name> <local-dir> <remote-dir> sync git-tracked and untracked files, keep node_modules
# sbx exec <name> <script> run a shell script remotely, exit with its status
# sbx get <name> <remote-file> <local-file>
# sbx put <name> <local-file> <remote-file>
# sbx rm <name>... permanently remove sandboxes
# sbx clean remove every sandbox tagged with your owner tag
# shellcheck disable=SC2016 # single-quoted scripts are expanded by the remote shell
set -eu
: "${SBX_SCOPE:?set SBX_SCOPE to your team slug}"
: "${SBX_PROJECT:?set SBX_PROJECT to your project name}"
owner=${SBX_OWNER:-${USER:-agent}}
vcpus=${SBX_VCPUS:-8} # Pro maximum; Hobby allows 4
timeout=${SBX_TIMEOUT:-3h} # session length; Hobby allows 45m
exec_timeout=${SBX_EXEC_TIMEOUT:-2h}
sb() { # sb <subcommand> [args...]
sub=$1
shift
vercel sandbox "$sub" --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$@"
}
# `vercel sandbox exec` exits 0 even when the remote command fails, so the
# remote shell prints the script's exit status and remote() returns it.
remote() { # remote <name> <script> [args...]
name=$1
script=$2
shift 2
log=$(mktemp)
sb exec --timeout "$exec_timeout" "$name" -- \
sh -c 'sh -c "$0" sh "$@"; echo "__sbx_exit=$?"' "$script" "$@" | tee "$log"
code=$(sed -n 's/^__sbx_exit=//p' "$log" | tail -n 1)
rm -f "$log"
return "${code:-1}"
}
push() { # push <name> <local-dir> <remote-dir>
git -C "$2" rev-parse --is-inside-work-tree > /dev/null
tgz=$(mktemp)
(cd "$2" && git ls-files -z --cached --others --exclude-standard |
COPYFILE_DISABLE=1 tar -czf "$tgz" --null -T -)
sb copy "$tgz" "$1:$3.tgz"
rm -f "$tgz"
remote "$1" '
set -e
dest=$1
rm -rf "$dest.new"
mkdir -p "$dest.new"
tar -xzf "$dest.tgz" -C "$dest.new"
rm -f "$dest.tgz"
if [ -d "$dest" ]; then
(cd "$dest" && find . -maxdepth 4 -type d -name node_modules -prune -print) > "$dest.keep"
while IFS= read -r keep; do
[ -e "$dest.new/$keep" ] && continue
mkdir -p "$(dirname "$dest.new/$keep")"
mv "$dest/$keep" "$dest.new/$keep"
done < "$dest.keep"
rm -rf "$dest" "$dest.keep"
fi
mv "$dest.new" "$dest"' "$3" > /dev/null
}
cmd=${1:?usage: sbx create|push|exec|get|put|rm|clean ...}
shift
case "$cmd" in
create)
name=${1:?usage: sbx create <name>}
snapshot=${SBX_SNAPSHOT:-$(cat BASE_SNAPSHOT)}
sb create --name "$name" --non-persistent --snapshot "$snapshot" \
--vcpus "$vcpus" --timeout "$timeout" \
--tag "app=$SBX_PROJECT" --tag "owner=$owner" --silent
echo "$name"
;;
push)
push "${1:?name}" "${2:?local dir}" "${3:?remote dir}"
;;
exec)
name=${1:?usage: sbx exec <name> <script>}
shift
remote "$name" "$*"
;;
get)
rm -f "${3:?local file}"
sb copy "${1:?name}:${2:?remote file}" "$3"
[ -f "$3" ] || { echo "sbx: could not copy $1:$2" >&2; exit 1; }
;;
put)
[ -f "${2:?local file}" ] || { echo "sbx: no such file: $2" >&2; exit 1; }
sb copy "$2" "${1:?name}:${3:?remote file}"
;;
rm)
: "${1:?usage: sbx rm <name>...}"
sb remove "$@"
;;
clean)
# `list` shows 50 sandboxes per page; run `sbx clean` again if more remain.
names=$(sb list --all --tag "owner=$owner" | awk 'NR > 1 && NF && $1 != "More" { print $1 }')
# shellcheck disable=SC2086 # one word per sandbox name
if [ -n "$names" ]; then sb remove $names; fi
;;
*)
echo "usage: sbx create|push|exec|get|put|rm|clean ..." >&2
exit 2
;;
esac
典型的 Agent 会话:
sbx create exp-parser
sbx push exp-parser . /vercel/sandbox/cand
sbx exec exp-parser 'cd /vercel/sandbox/cand && sh /vercel/sandbox/prepare.sh && npm test'
sbx get exp-parser /tmp/results.json ./results.json
sbx rm exp-parser
在封装脚本旁记录工作流(简短的 SANDBOX.md):快照 ID、基础环境包含的内容、准备步骤、运行测试套件的方法,以及已知的仅由环境导致的失败。让每个 Agent 的指令都指向该文件。
常见问题
- **虚假成功:**远程命令失败时,
vercel sandbox exec仍会以 0 退出。请读取打印出的退出状态,或使用sbx exec。 - **内存不足:**大型编译可能会被终止。远程退出状态 137 表示进程收到了 SIGKILL,通常是 OOM killer 导致的。在套餐额度内升级规格,或在达到上限时降低并行度,而不是盲目重试。
- **会话超时导致工作丢失:**非持久化沙盒会在会话停止时丢弃文件系统。请在超时前复制结果,并将超时时长设置为足以覆盖整个任务。
- 残留沙盒:
stop不会释放沙盒名称,也不会删除沙盒。请使用remove,并通过list --all清理残留项。 - **快照过期:**从旧基础环境启动的任务可能遇到工具链版本不匹配。版本变更时,请重建快照,或在任务沙盒中更新工具。
- **共享沙盒:**两个 Agent 使用同一个沙盒会破坏彼此的目录树。每个沙盒只分配一个负责人。
- **运行中耗尽配额:**在 Hobby 上,月度额度用尽后会暂停创建沙盒;在 Pro 上,Spend Management 限制可能会暂停项目。分小步提交工作,边做边将结果写入磁盘,并确保脚本具备幂等性,这样替换后的 Agent 就能接续工作,而不必从头开始。