mcpField
D
devboxes

devboxes

github.com/namespacelabs云与 DevOps22.2k 次安装5 周前更新
代码仓库

关于 devboxes

这是用于操作 Namespace devboxes 的技能,面向需要在远程 Linux 或 macOS 机器上开发和运行命令的场景。它涵盖机器创建与管理、工作区文件同步、工具链配置和远程命令执行。

主要功能

  1. 01创建和管理远程 devbox
  2. 02选择镜像与机器规格
  3. 03上传和下载工作区文件
  4. 04配置工具链与代码仓库
  5. 05使用 devbox exec 运行命令

适用场景

  1. 01在远程机器上运行命令
  2. 02使用临时 devbox 进行测试
  3. 03将本地改动传到远程工作区

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/namespacelabs/agent-skills --skill devboxes

安装后在 Claude Code 中输入/devboxes确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
cli-setup.md
inside-a-devbox.md
run-tests.md

详细介绍

Namespace devboxes

Namespace devbox 是远程 linux/amd64 或 macos/arm64 机器。Linux devbox 已安装 Docker。本技能介绍使用 devbox 的通用构建模块——创建 devbox、传输文件、准备工作区、安装工具链、使用 devbox exec 运行命令、通过 devbox.so 与队友共享 Web 工作,以及管理 devbox 生命周期。

在本技能中:

  • devbox - Namespace 机器,由其 name 标识。
  • <name> - 传递给所有 devbox 子命令的 devbox 名称。

根据调用者的意图,devbox 可以长期运行、在多个任务间重复使用,也可以立即销毁。创建时传递 --ephemeral 可将其标记为一次性机器。

对于运行一次后销毁的工作流(单脚本或测试运行,可选分片),请参阅 references/run-tests.md。

0. 确认当前运行位置

以下内容均假设你在其他位置操控 devbox。首先检查你是否已经在 devbox 上——工具和身份验证方式有所不同:

[ -n "${NAMESPACE_DEVBOX_WORKSPACE_DIR:-}" ] && echo "on a devbox"

Devbox Agent 会将该变量注入机器上的每个进程,因此这是一种可靠的单行检查方式。如果已设置,请先阅读 references/inside-a-devbox.md,再进行其他操作。这里有两点不同:

  • 普通命令无需包装器。 你就在这台机器上。直接运行 go test、git 并编辑文件;对于当前 devbox 范围内的工作,跳过下面的 devbox 预检。
  • 两个 CLI 均已可用——不要运行 devbox login。 boxctl 和 devbox 均安装在 ~/.devbox/bin 中。devbox CLI 使用 workload 凭据进行身份验证,该凭据代表租户而非个人:它可以操作具有工作区访问权限的 devbox,但无法操作仅对创建者私有的 devbox——通常也包括你当前所在的机器。因此,boxctl 通过套接字连接本地 Agent,无需凭据,所以它才是操作当前 devbox 的工具,而不只是速度更快的选择。注意,在这里运行 devbox auth check-login 时,即使 CLI 可用,它仍会报告“Not logged in”;若据此采取行动,会进入你无法完成的浏览器登录流程。参考文档还涵盖其他内容,包括使用 --access_mode workspace 创建同级机器。

预检 从 PATH 或平台默认安装位置解析 devbox;如果 PATH 已过时,则使用绝对路径;只有在 CLI 不存在时,才自行安装 Devbox CLI。运行解析出的 CLI 的 auth check-login;如果需要登录,则运行 devbox login,让用户完成浏览器流程,并等待命令返回。有关确切步骤,包括会话过期和工作区切换,请参阅 references/cli-setup.md。不要尝试从其他工具签发或借用凭据。

1. 创建 devbox

如果任务需要项目工具链(Go、Node、Xcode 等),请选择已包含相应工具链的镜像,以避免每次运行都重新安装依赖:运行一次 devbox image list -o json,查找现有项目镜像,并在适用时使用其中一个。缓存查询结果——重复调用不会带来新信息。

对于不需要项目工具链的临时工作(一次性命令、临时 VM、快速平台检查),完全跳过镜像发现,直接使用 builtin:default。在 Linux 上,builtin:default 已包含常用工具链,例如 Go,因此对于许多任务,它已足够。一般而言,对于较简单的 Linux 场景,使用 builtin:default 并直接安装依赖。

重要 将 devbox image list -o json 输出中的简短 name 字段传递给 --image(例如 <org>/<image> 或 builtin:default),不要传递完整的 repository URL——完整引用通常会失败。确保镜像与请求的平台相匹配。

devbox create \
  --name <name> \
  [--platform <linux/amd64|macos/arm64>] \
  --image <image> \
  --size <size> \
  [--ephemeral] \
  [--checkout <repo-url>] \
  --purpose "<purpose>"

如果未指定 --platform,则默认使用 Linux/amd64。任务需要 macOS 或 Apple Silicon 时,传递 --platform macos/arm64。 任务完成后如果 devbox 无需保留,请添加 --ephemeral;如果需要保留,则省略该参数。

重要(工作区检出默认行为) 如果未设置 --checkout,Namespace 会使用工作区配置的默认仓库并自动克隆。当不需要仓库时(例如用于执行一次性命令的临时 VM),传入 --no_checkout 以完全跳过克隆。

--checkout <repo-url>(例如 [email protected]:org/repo.git)会将仓库克隆到 /workspaces/<repo-name>。如果因该仓库或组织无法检出而导致创建失败:

  1. 让刚创建的 devbox 过期(devbox expire <name> --force),以释放容量。
  2. 如果本地已安装 gh,则在不带 --checkout 的情况下重新创建 devbox,然后运行 devbox setup-github <name>,将你的 gh 令牌转发到 devbox。成功后,通过 devbox exec <name> -- 在 devbox 中运行 git clone --depth=1 <repo-url> /workspaces/<repo-name>。对于大型单体仓库,务必使用 --depth=1——完整克隆可能运行数分钟,进度输出稀疏,看起来就像卡住了一样。重要 转发的 gh 令牌仅用于 HTTPS 身份验证——请通过 https://github.com/<org>/<repo>.git 克隆,而不是 [email protected]:...。
  3. 如果未安装 gh,或者 devbox setup-github / devbox 内的 git clone 失败,请指示用户将其 GitHub 组织关联到 Namespace:https://cloud.namespace.so/workspace/workspace/integrations?integration=github——未完成关联则无法继续检出。

重要(区分大小写的组织 slug) Namespace 的关联查找会区分 --checkout 中 GitHub 组织/所有者部分的大小写。请使用用户提供的仓库 URL 中(或 git remote -v 返回的)组织/所有者大小写形式。检出失败时,绝不要尝试其他大小写形式(例如将组织名改为小写)来“修复”问题。

Linux 规格:s(4 vCPU / 8 GB)、m(8 vCPU / 16 GB)、l(16 vCPU / 32 GB)、xl(32 vCPU / 64 GB)。macOS 规格:m(6 vCPU / 14 GB)和 l(12 vCPU / 28 GB)。仅在执行范围有限的命令或小型定向工作负载时使用最小规格;如果工作负载依赖项较多或需要构建多个软件包,请优先选择更大规格,以避免内存溢出。如果进程因 signal: killed 被终止,请升级到更大规格后重试。

并行进行创建和本地准备 devbox create 会一直阻塞,直到机器就绪,这需要几十秒。利用这段时间:将 devbox create 作为后台任务运行,然后立即计算任何本地 git diff,并在本地编写设置和运行脚本。创建完成后,再上传并执行。这样可以消除空等时间。

注意 Devbox 创建可能会因 Namespace 套餐对资源等级或实例数量的限制而失败。如果发生这种情况:继续之前先询问用户,运行 devbox list 并询问是否可以让任何可用 devbox 过期或重复使用,然后重试;作为最后的办法,尽量将工作合并到更少的 devbox 中,而不是因此停滞。

对于适合在多个 devbox 间分片运行的测试或脚本,请参阅 references/run-tests.md。

2. 准备工作区并安装工具链

上传和下载文件
devbox upload <name> <local-path>  <remote-path> [--mkdir]
devbox download <name> <remote-path> <local-path>
  • <remote-path> 必须是完整文件路径。末尾带 / 会失败。
  • --mkdir 会创建缺失的父目录;它不会将目标路径设为目录。
  • 不会保留可执行权限。上传脚本后,请使用 devbox exec 运行 chmod +x。
  • 请写入 /workspaces 或 $HOME 下。 远程用户权限不足(devbox,uid 1001),并非 root,因此上传到系统路径时会因父目录权限不足而失败——mkdir: cannot create directory '/srv/www': Permission denied——而 --mkdir 也无法解决,因为问题在于权限不足,而非目录缺失。要提供网页服务?/workspaces/<name>/ 是合适的位置,而不是 /srv 或 /var/www。
准备工作区

在 UI 中配置了仓库的 devboxes 命名空间会在启动时将其自动克隆到 /workspaces/<repo-name>。同步前务必先检查此处:

devbox exec <name> -- ls /workspaces/

如果仓库已存在,请直接使用该路径。自动克隆的仓库反映的是默认分支,因此其中没有你的本地更改——运行任何操作前,必须先将这些更改同步过去。

选择能覆盖所需文件的最低成本同步方式。 有两种方法,通常简单的方法就足够:

(a) 默认方式:发送工作树。 对于小型或中型仓库,直接复制磁盘上的文件。这样一步即可包含已跟踪的修改和未跟踪文件,无需考虑提交或基准,也不会悄悄遗漏任何内容。可以直接上传少量文件,或者将整个目录打包成 tar:

# A few files - upload them directly.
devbox upload <name> ./calc.go /workspaces/<repo-name>/calc.go --mkdir

# More than a handful - tar the tree, excluding .git and build output.
tar --exclude .git -czf /tmp/tree.tgz -C <repo-root> .
devbox upload <name> /tmp/tree.tgz /tmp/tree.tgz
devbox exec   <name> -- mkdir -p /workspaces/<repo-name>
devbox exec   <name> -- tar -xzf /tmp/tree.tgz -C /workspaces/<repo-name>

(b) 大型仓库:对齐提交,然后应用补丁。 当工作树大到复制它比克隆仓库更慢时,可以让 devbox 自己的克隆负责大部分工作,只发送差异。这种方式需要更多操作,因此只有在 (a) 确实太慢时才使用。

重要 devbox 克隆的是默认分支,因此差异和检出操作必须指定同一个提交,否则无关文件可能会被覆盖:

BASE=$(git merge-base origin/main HEAD)
git diff "$BASE" > /tmp/changes.patch   # add --binary if the diff touches generated/binary files

# For git, prefer `git -C <path>` over `cd <path> && git ...` - no cwd to get wrong.
devbox exec   <name> -- git -C /workspaces/<repo-name> fetch --depth=1 origin "$BASE"
devbox exec   <name> -- git -C /workspaces/<repo-name> checkout "$BASE"
devbox upload <name> /tmp/changes.patch /tmp/changes.patch
devbox exec   <name> -- git -C /workspaces/<repo-name> apply /tmp/changes.patch
devbox exec   <name> -- git -C /workspaces/<repo-name> status --short

重要(导致 (b) 有风险的失败模式) git diff 只包含已跟踪文件。你尚未执行 git add 的新文件不会被它发现,因此基于补丁的同步会悄悄遗漏这些文件;如果遗漏的是一个新测试,你就会自信地报告一个基于从未存在过的代码得出的结果。因此,(b) 单独使用并不完整:还要发送未跟踪文件。

git ls-files --others --exclude-standard    # exactly what a patch will MISS

可以直接上传这些文件、将它们加入 tar 包,或者在文件很多时使用 rsync:

# for rsync - configure native ssh
devbox configure-ssh <name>
# After running this, you can connect with:
ssh <name>.devbox.namespace
# Then list untracked files and feed them to rsync
git ls-files --others --exclude-standard | \
  rsync -av --files-from=- . \
  <name>.devbox.namespace:/workspaces/<repo-name>/

验证后再相信结果。 确认需要发送的文件确实已到位,这样同步遗漏会立即暴露,而不是之后导致错误答案:

devbox exec <name> -- ls -la /workspaces/<repo-name>

如果仓库完全没有远程仓库(例如临时仓库或仅本地仓库),则无法使用 (b)——请使用 (a)。

安装工具链

如果缺少某个工具,只安装工作负载所需的工具。

重要 安装前先检查工具是否已存在——在 Linux 上,builtin:default 附带的工具比你想象的更多,包括 Go 等语言。先尝试运行命令,再考虑手动安装。

使用工具自身的标志进行探测,该标志对应的是实际可执行文件:

devbox exec <name> -- go version

这种方式无法使用 command -v。它是 shell 内置命令,而 devbox exec 不经 shell 直接运行命令,因此 devbox exec <name> -- command -v go 会失败,并显示 exec: "command": executable file not found in $PATH——这看起来像是工具缺失,实际却不是。如果要使用 command -v,请通过 shell 运行:

devbox exec <name> -- bash -lc 'command -v go >/dev/null && go version || echo MISSING_GO'

重要 对于脚本使用的每个 CLI 工具,都要先检查是否已存在,仅在缺失时安装。使用适用于平台的安装程序和制品。例如,在 Linux/amd64 上:

devbox exec <name> -- apt-get install -y --no-install-recommends \
    git ca-certificates curl tar build-essential
devbox exec <name> -- curl -fsSL -o /tmp/go.tgz https://go.dev/dl/go<version>.linux-amd64.tar.gz
devbox exec <name> -- tar -xzf /tmp/go.tgz -C /usr/local

3. 使用 devbox exec 运行命令

重要 针对不同 devbox 的 devbox exec 调用要并行运行。不要串行执行互不依赖的工作。

devbox exec <name> -- <cmd> <args...>

devbox ssh <name> 仍可用于交互式 Shell 和依赖 TTY 的工作流。非交互式命令优先使用 devbox exec。

替代方案:原生 SSH 如果工作流使用依赖标准 SSH 工具(scp、rsync 等)的工具,请运行一次 devbox configure-ssh <name>,在你的 ~/.ssh/config 中写入一条配置。之后,即可通过 <name>.devbox.namespace 访问 devbox。命令优先使用 devbox exec;只有在明确需要标准工具时才使用原生 SSH。

重要(exec 不会为你启动 Shell,但你可以指定启动) devbox exec 会直接运行命令,因此默认不会解析 &&、;、重定向和变量展开等 Shell 运算符。devbox exec <name> -- cd /src && make 不会按预期运行。

完成多步骤工作有两种方式,各有取舍:

简短的多步骤工作——显式调用 Shell。 只需一次往返,但出错后需要重新运行:

devbox exec <name> -- bash -lc 'cd /workspaces/<repo-name> && go build ./... && go test ./...'

较长或可复用的逻辑——上传脚本。 当逻辑较长、需要仔细处理引号,或希望在机器上记录确切步骤时,多几次往返(upload、chmod、运行)是值得的。请注意,脚本中的错误需要重新上传并再次运行 chmod,因此在仍在迭代时优先使用 bash -lc:

devbox upload <name> /tmp/script.sh /tmp/script.sh
devbox exec   <name> -- chmod +x /tmp/script.sh
devbox exec   <name> -- bash /tmp/script.sh

使用 bash -lc 时要特别留意引号:将整个程序用单引号括起来,让远程 Shell 展开 $VARS,否则它们会在命令离开你的机器前就在本地展开。

分离运行的命令和保留的日志

对于长时间运行的命令,请使用 devbox exec -d。它会启动命令后立即返回,并输出一个 exec ID。使用该 ID,通过 devbox logs 流式查看保留的输出和实时输出。devbox logs list 会显示之前的执行记录及其状态。

devbox exec -d <name> -- <cmd> <args...>
# exec_<id>

devbox logs <name> <exec-id>
devbox logs list <name>

重要 在执行 set -e 前,预先检查所有必需的 CLI 工具,确保缺少工具时会显示明确消息,而不是产生难以诊断的失败:command -v <tool> >/dev/null || { echo "MISSING_TOOL: <tool>"; exit 127; }。如果退出码为 127,或出现 MISSING_TOOL 标记,请安装依赖后重新运行——不要报告运行失败。

重要 将所有脚本输出写入远程日志文件,默认只返回简短摘要。

cat > /tmp/run.sh <<'EOF'
#!/bin/bash
export PATH=/usr/local/go/bin:$PATH
command -v <tool> >/dev/null || { echo "MISSING_TOOL: <tool>"; exit 127; }
set -euo pipefail
mkdir -p /workspaces/tmp
export TMPDIR=/workspaces/tmp
LOG=/workspaces/run.log

cd /workspaces/<repo-name>
status=0
<workload-cmd> >"$LOG" 2>&1 || status=$?

echo "exit=$status log=$LOG bytes=$(wc -c <"$LOG")"
exit "$status"
EOF
devbox upload <name> /tmp/run.sh /tmp/run.sh
devbox exec   <name> -- chmod +x /tmp/run.sh
devbox exec   <name> -- bash /tmp/run.sh

# Pull the full log only if the summary shows a non-zero exit.
# devbox download <name> /workspaces/run.log /tmp/run.log

注意 在输出摘要前捕获工作负载的退出码(status=0; cmd || status=$?)。除非另有说明,只对摘要显示非零退出码的 devbox 使用 devbox download。

关于测试运行器的具体指南(分片、并行运行、准备并测试的流程、结果报告),请参阅 references/run-tests.md。

4. 生命周期

devbox create --name <name> [--platform <linux/amd64|macos/arm64>] --image <image> --size <size> [--ephemeral] [--checkout <repo-url>] --purpose "<purpose>"
devbox exec <name> -- <cmd>
devbox exec -d <name> -- <cmd>                                     # run in the background and print an exec ID
devbox logs <name> <exec-id>                                       # stream retained and live output
devbox logs list <name>                                            # inspect retained executions and status
devbox ssh <name>                                                  # open an interactive shell; prefer exec for commands
devbox list [-o json]                                              # inspect running devboxes
devbox upload <name> <local-path> <remote-path>                    # transfer files to devbox
devbox download <name> <remote-path> <local-path>                  # retrieve files from devbox
devbox configure-ssh <name>                                        # add to ~/.ssh/config for native ssh/scp/rsync
devbox url access <name> [--mode <private|workspace>] -o json      # inspect or change devbox.so access
devbox url expose <name> --port <port> [--name <purpose>] -o json  # create a persistent devbox.so URL
devbox url get <name> (--port <port> | --name <purpose>) -o json   # retrieve an exposed URL
devbox url list <name> -o json                                     # list exposed URLs
devbox url unexpose <name> (--port <port> | --name <purpose>)      # remove an exposed URL
devbox port-forward <name> --ports <local:remote,...>              # forward devbox ports to localhost (e.g. a dev server or DB)
devbox shutdown <name>                                             # stop a devbox without destroying it
devbox expire <name> --force                                       # tear down a devbox
长时间运行工作期间保持 devbox 运行

设置了空闲超时的 devbox 在没有活动迹象时会自动停止。Devbox Agent 会将正在运行的 devbox exec 或 SSH 命令视为活动状态,并在命令整个运行期间保持此状态。创建或连接终端会话,以及通过公开的 devbox.so URL 接收 HTTP 响应,只会在有限时间内被视为近期活动。未被正在运行的 exec 或 SSH 命令覆盖的工作,需要显式标记:

devbox exec <name> -- boxctl task mark <task>          # hold the devbox busy
devbox exec <name> -- boxctl task clear-mark <task>    # release it
devbox exec <name> -- boxctl task list                 # what is currently holding it

每个 devbox 都预装了 boxctl,因此无需在 box 上安装任何内容,就能从你的机器运行上述操作。在 devbox 内部运行时,去掉 devbox exec <name> -- 前缀。

标记所有将在没有正在运行的 devbox exec 或 SSH 命令时无人值守运行的任务:在终端会话中启动的通宵任务、迁移、队列工作进程,或尚无人访问的开发服务器。只要前台或分离运行的 devbox exec 命令仍在运行,就无需标记。没有这两种活动时,机器可能会在任务进行中停止,导致工作中断。 重要 标记没有 TTL,也不会被清理。留下的标记会让 devbox 一直保持唤醒状态并持续产生费用,从而彻底绕过空闲超时。因此,始终要将 mark 与对应的 clear-mark 配对使用,失败路径也不例外。这两条命令都是幂等的;如果标记已存在或已清除,命令仍会以状态码 0 退出,因此可安全地用于陷阱处理和重试。陷阱处理模式请参阅 references/inside-a-devbox.md。

标记只能阻止 空闲 超时。devbox shutdown 和 devbox expire 仍会停止机器。

重要 这些 devbox url 命令要求 devbox CLI v0.0.182 或更高版本。使用 devbox version 检查;如果已安装的版本较旧,请先运行 devbox update 再使用这些命令。

选择谁可以打开 devbox.so URL 每个 devbox 的所有公开 URL 共用一种访问模式:

  • private - 仅 devbox 所有者可访问。
  • workspace - 同一 Namespace 工作区的成员可访问。

URL 模式最初遵循 devbox 的常规访问模式,但之后会单独配置。更改 URL 访问权限不会授予或移除对 devbox 的 SSH、exec 或文件访问权限。

独立检查或更改 Devbox 级别的 URL 模式:

devbox url access my-box -o json
devbox url access my-box --mode workspace -o json

重要 devbox url expose ... --access <mode> 会在公开端口时更改同一个 Devbox 级别设置。此设置会影响该 devbox 上所有现有和未来公开的 URL;它不会只为新 URL 设置访问权限。不支持按 URL 设置访问模式。如果 URL 需要面向不同受众,请在更改访问权限前征求确认,或使用单独的 devbox。

与队友分享 Web 工作 当用户希望队友能够查看 devbox 中运行的工作时,请使用 --access workspace 公开其端口,并返回生成的 devbox.so URL。命令退出后,该 URL 仍可访问。如果已知端口用途,请传入 --name,以便之后更容易查找和移除该 URL。对于 Agent 工作流,优先使用 JSON 输出。

重要(如何验证公开的 URL——以及不该如何验证) devbox url expose 成功并返回 URL,就是确认。到此为止,并将 URL 提供给用户。

不要尝试获取该 URL 来“证明”它有效。devbox.so URL 需要经过身份验证的用户会话,而你既没有此类会话,也无法生成;curl 会返回 401 unauthorized,任何 API 或 ID 令牌都无法改变这一点。这个 401 不代表失败,也不能说明任何需要你处理的问题。在此技能中,执意追求 200 是代价最高的徒劳尝试:它会浪费数分钟尝试令牌端点和 SSH 隧道,只为再次确认 CLI 已经告知你的事实。

如果你想在分享前确认 服务端 确实已启动,请在 devbox 内检查,因为此处不涉及网关身份验证:

devbox exec <name> -- curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:<port>/

将服务绑定到 0.0.0.0,而不是 127.0.0.1,否则 devbox.so 代理无法访问它们。

devbox url expose my-box --port 3000 --name web --access workspace -o json

如果用户没有要求分享,请省略 --access 并保留当前模式。如果用户的分享意图不明确,请检查当前模式,不要扩大访问范围。如果用户明确要求 devbox 上的每个公开 URL 都仅限所有者访问,请在公开新端口前设置为 private:

devbox url access my-box --mode private -o json
devbox url expose my-box --port 3000 --name web -o json

对于仅限本地访问的服务或非 Web 服务,请使用 devbox port-forward。例如:devbox port-forward my-box --ports 3000:3000,5432:5432 会将端口映射到 localhost:3000 和 localhost:5432。该命令会一直占用终端,直到按下 Ctrl+C,因此请在专用终端中运行,或将其作为后台进程运行。

是否以及何时调用 devbox expire 取决于调用者的意图——references/run-tests.md 中的测试套件工作流会在结束时拆除环境;其他用例可能会让 devbox 保持运行。

重要 如果因缺少依赖项而失败,请安装依赖项并重试失败的命令。上传的脚本也应如此处理。

评论

支持 Markdown