devboxes

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Namespace devboxes

Namespace devboxes

Namespace devboxes are remote
linux/amd64
or
macos/arm64
machines. Linux devboxes have Docker available. This skill describes the general building blocks for working with devboxes - creating them, transferring files, hydrating a workspace, installing toolchains, running commands with
devbox exec
, sharing web work with teammates through
devbox.so
, and managing the devbox lifecycle.
Throughout this skill:
  • devbox - a Namespace machine, identified by its
    name
    .
  • <name>
    - the devbox name passed to all
    devbox
    subcommands.
The devbox may be long-lived, reused across tasks, or torn down immediately depending on the caller's intent. Pass
--ephemeral
at creation time to mark it as disposable.
For run-once-then-destroy workflows (single-script or test runs, optional sharding), see references/run-tests.md.
Namespace devboxes 是远程的
linux/amd64
或
macos/arm64
机器。Linux devbox 自带 Docker。本 skill 描述使用 devbox 的基础模块:创建它们、传输文件、加载(hydrate)工作区、安装工具链、使用
devbox exec
运行命令、通过
devbox.so
与队友共享 Web 工作,以及管理 devbox 生命周期。
在整个 skill 中:
  • devbox - 一台 Namespace 机器,由其
    name
    标识。
  • <name>
    - 传递给所有
    devbox
    子命令的 devbox 名称。
devbox 可以是长期存活、跨任务复用,也可以根据调用者的意图立即销毁。在创建时传入
--ephemeral
将其标记为可丢弃。
对于“运行一次即销毁”的工作流(单脚本或测试运行、可选的分片),请参阅 references/run-tests.md。

0. Establish where you are running

0. 确定你正在哪里运行

Everything below assumes you are driving a devbox from somewhere else. First check whether you are already ON one - the tooling and the auth story are different:
bash
[ -n "${NAMESPACE_DEVBOX_WORKSPACE_DIR:-}" ] && echo "on a devbox"
The Devbox agent injects that variable into every process on the machine, so it is a reliable one-line check. If it is set, read references/inside-a-devbox.md before doing anything else. Two things are different there:
  • Ordinary commands need no wrapper. You are on the machine. Run
    go test
    ,
    git
    and file edits directly, and skip the
    devbox
    preflight below for work scoped to the devbox you are in.
  • Both CLIs are already usable - do not run
    devbox login
    .
    boxctl
    and
    devbox
    both ship in
    ~/.devbox/bin
    . The
    devbox
    CLI is authenticated by a workload credential, which acts as the tenant rather than as a person: it can drive workspace-access devboxes, but not ones private to their creator - including, usually, the machine you are on. That is why
    boxctl
    , which reaches the local agent over a socket and needs no credential, is the tool for the current devbox rather than merely the quicker one. Beware
    devbox auth check-login
    here: it reports "Not logged in" even while the CLI works, and acting on that leads to a browser login flow you cannot complete. The reference covers the rest, including
    --access_mode workspace
    for creating sibling boxes.
Preflight Resolve
devbox
from PATH or its platform's default install location; use the absolute path if PATH is stale, and install the Devbox CLI yourself only if it is absent. Run the resolved CLI's
auth check-login
; if login is required, run
devbox login
, let the user complete the browser flow, and wait for the command to return. See references/cli-setup.md for exact steps, including session expiry and workspace switching. Do not try to mint or borrow credentials from other tooling.
以下所有内容都假定你是从其他位置驱动 devbox 的。首先检查你是否已经在某个 devbox 内部——此时的工具和认证方式有所不同:
bash
[ -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 凭据进行认证,它以租户身份而非个人身份运作:它可以驱动 workspace 访问级别的 devbox,但不能驱动对其创建者私有的 devbox——通常包括你当前所在的这台机器。这就是为什么
    boxctl
    (通过 socket 访问本地 agent,且不需要凭据)是操作当前 devbox 的工具,而不仅仅是因为它更快。注意这里的
    devbox auth check-login
    :即使 CLI 能正常工作,它也会报告“Not logged in”,如果据此操作,会进入一个你无法完成的浏览器登录流程。其余内容(包括用于创建兄弟 box 的
    --access_mode workspace
    )由该 reference 文档说明。
预检 从 PATH 或平台默认安装位置解析
devbox
;如果 PATH 过期,请使用绝对路径;只有在缺失时才自行安装 Devbox CLI。运行解析出的 CLI 的
auth check-login
;如果需要登录,运行
devbox login
,让用户完成浏览器流程,并等待命令返回。具体步骤(包括会话过期和 workspace 切换)见 references/cli-setup.md。不要尝试从其他工具生成或借用凭据。

1. Create a devbox

1. 创建 devbox

If the task needs a project toolchain (Go, Node, Xcode, etc.), pick an image that already includes it to avoid reinstalling dependencies on every run: run
devbox image list -o json
ONCE to discover existing project images, and use one if it fits. Cache that result - repeating the call does not tell you anything new.
Skip image discovery entirely for scratch work that needs no project toolchain (a one-off command, a throwaway VM, a quick platform check) and go straight to
builtin:default
. On Linux,
builtin:default
already ships common toolchains - Go, for instance - so for many tasks it is the whole answer. For simpler Linux cases generally, fall back to
builtin:default
and install dependencies directly.
Important Pass the short
name
field from
devbox image list -o json
to
--image
(e.g.
<org>/<image>
or
builtin:default
), not the full
repository
URL - full references typically fail. Ensure the image matches the requested platform.
bash
devbox create \
  --name <name> \
  [--platform <linux/amd64|macos/arm64>] \
  --image <image> \
  --size <size> \
  [--ephemeral] \
  [--checkout <repo-url>] \
  --purpose "<purpose>"
Linux/amd64 is the default when
--platform
is omitted. Pass
--platform macos/arm64
when the task requires macOS or Apple Silicon.
Add
--ephemeral
when the devbox does not need to persist after a task is complete; omit it when persistence is required.
Important (workspace checkout default) If
--checkout
is unset, Namespace uses the workspace's configured default repo and clones it automatically. When no repository is needed (e.g. a scratch VM for a one-off command), pass
--no_checkout
to skip cloning entirely.
--checkout <repo-url>
(e.g.
git@github.com:org/repo.git
) clones the repository into
/workspaces/<repo-name>
. If creation fails because checkout is unavailable for the repo or org:
  1. Expire the just-created devbox (
    devbox expire <name> --force
    ) to free capacity.
  2. If
    gh
    is installed locally, recreate the devbox WITHOUT
    --checkout
    , then run
    devbox setup-github <name>
    to forward your
    gh
    token into the devbox. Once that succeeds, run
    git clone --depth=1 <repo-url> /workspaces/<repo-name>
    inside the devbox via
    devbox exec <name> --
    . Always use
    --depth=1
    for large monorepos - full clones can run for minutes with sparse progress output and look identical to a hang. Important The forwarded
    gh
    token authenticates HTTPS only - clone via
    https://github.com/<org>/<repo>.git
    , not
    git@github.com:...
    .
  3. If
    gh
    is not installed, or
    devbox setup-github
    / the in-devbox
    git clone
    fails, instruct the user to link their GitHub organization to Namespace at https://cloud.namespace.so/workspace/workspace/integrations?integration=github - checkout cannot proceed without it.
Important (case-sensitive org slug) The Namespace association lookup is case-sensitive on the GitHub org/owner segment of
--checkout
. Use the org/owner casing EXACTLY as it appears in the repo URL the user gave you (or as returned by
git remote -v
). NEVER try alternative casings (e.g. lowercasing the org) as a "fix" when checkout fails.
Linux sizes:
s
(4 vCPU / 8 GB),
m
(8 vCPU / 16 GB),
l
(16 vCPU / 32 GB),
xl
(32 vCPU / 64 GB). macOS sizes:
m
(6 vCPU / 14 GB) and
l
(12 vCPU / 28 GB). Use the smallest size only for narrow commands or small targeted workloads; prefer bigger when the workload has large dependencies or builds multiple packages, to avoid OOM. If a process is killed with
signal: killed
, upgrade to a larger size and retry.
Overlap creation with local prep
devbox create
blocks until the machine is ready, which takes tens of seconds. Use that time: run
devbox create
as a background task, then immediately compute any local git diff and write the setup and run scripts locally. Once creation completes, upload and execute. This eliminates idle waiting.
Note Devbox creation might fail due to Namespace plan limits on resource tiers or instance counts. If this happens: PROMPT THE USER BEFORE PROCEEDING run
devbox list
and ask to expire or reuse any of the available devboxes, then retry; As a last resort, consolidate work across fewer devboxes rather than blocking.
For test or script runs that benefit from sharding across multiple devboxes, see references/run-tests.md.
如果任务需要项目工具链(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——完整引用通常会失败。确保镜像与请求的平台匹配。
bash
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
;需要持久化时省略它。
重要(workspace checkout 默认行为) 如果未设置
--checkout
,Namespace 会使用 workspace 配置的默认仓库并自动克隆它。当不需要任何仓库时(例如用于一次性命令的临时 VM),传入
--no_checkout
以完全跳过克隆。
--checkout <repo-url>
(例如
git@github.com:org/repo.git
)会将仓库克隆到
/workspaces/<repo-name>
。如果因为该仓库或组织无法 checkout 而导致创建失败:
  1. 销毁刚创建的 devbox(
    devbox expire <name> --force
    )以释放容量。
  2. 如果本地安装了
    gh
    ,在不带
    --checkout
    的情况下重新创建 devbox,然后运行
    devbox setup-github <name>
    将你的
    gh
    token 转发到 devbox。成功后,通过
    devbox exec <name> --
    在 devbox 内运行
    git clone --depth=1 <repo-url> /workspaces/<repo-name>
    。对于大型 monorepo,始终使用
    --depth=1
    ——完整克隆可能运行数分钟且进度输出稀疏,看起来与卡死无异。重要 转发的
    gh
    token 仅支持 HTTPS 认证——请通过
    https://github.com/<org>/<repo>.git
    克隆,而不是
    git@github.com:...
    。
  3. 如果未安装
    gh
    ,或者
    devbox setup-github
    / devbox 内的
    git clone
    失败,指示用户将其 GitHub 组织关联到 Namespace:https://cloud.namespace.so/workspace/workspace/integrations?integration=github - 没有此关联,checkout 无法继续。
重要(组织 slug 区分大小写) Namespace 对
--checkout
的 GitHub org/owner 段的关联查询区分大小写。请使用用户给你的仓库 URL 中出现的 org/owner 大小写(或
git remote -v
返回的大小写)完全一致。当 checkout 失败时,绝不要尝试其他大小写形式(例如将组织名小写)作为“修复”。
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)。只在狭窄命令或小型定向工作负载时使用最小规格;当工作负载具有大量依赖或构建多个包时,优先使用更大规格,以避免 OOM。如果进程因
signal: killed
被终止,升级到更大规格并重试。
将创建过程与本地准备工作重叠
devbox create
会阻塞直到机器就绪,这需要数十秒。利用这段时间:将
devbox create
作为后台任务运行,然后立即计算本地 git diff,并在本地编写 setup 和 run 脚本。创建完成后,上传并执行。这样可以消除空闲等待。
注意 devbox 创建可能因 Namespace 套餐对资源层级或实例数量的限制而失败。如果发生这种情况:在继续之前提示用户 运行
devbox list
,询问是否可以过期或复用任何可用 devbox,然后重试;作为最后手段,将工作合并到更少的 devbox 上,而不是阻塞。
对于适合跨多个 devbox 分片的测试或脚本运行,请参阅 references/run-tests.md。

2. Hydrate the workspace and install toolchains

2. 加载工作区(hydrate)并安装工具链

Upload and download files

上传和下载文件

bash
devbox upload <name> <local-path>  <remote-path> [--mkdir]
devbox download <name> <remote-path> <local-path>
  • <remote-path>
    MUST be a full file path. A trailing
    /
    fails.
  • --mkdir
    creates missing parent directories; it does NOT make the target a directory.
  • The executable bit is NOT preserved. Run
    chmod +x
    with
    devbox exec
    after uploading scripts.
  • Write under
    /workspaces
    or
    $HOME
    .
    The remote user is unprivileged (
    devbox
    , uid 1001), not root, so an upload to a system path fails on the parent directory -
    mkdir: cannot create directory '/srv/www': Permission denied
    - and
    --mkdir
    cannot rescue it, because the problem is permission, not absence. Serving a page?
    /workspaces/<name>/
    is the natural home, not
    /srv
    or
    /var/www
    .
bash
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
    。

Hydrate the workspace

加载(hydrate)工作区

Namespace devboxes configured with a repo in the UI auto-clone it to
/workspaces/<repo-name>
on startup. Always check there first before syncing:
bash
devbox exec <name> -- ls /workspaces/
If the repo is already present, use that path directly. The auto-cloned repo reflects the default branch, so it does NOT have your local work on it - you must get that across before running anything.
Pick the cheapest sync that covers your files. Two approaches, and the simple one is usually right:
(a) Default: ship the working tree. For a small or medium repo, copy the files as they are on disk. This captures tracked edits and untracked files in one step, needs no reasoning about commits or bases, and cannot silently omit anything. Upload a handful of files directly, or tar the tree for more:
bash
undefined
Namespace 在 UI 中配置了仓库的 devbox 会在启动时自动将其克隆到
/workspaces/<repo-name>
。在同步之前,始终先在那里检查:
bash
devbox exec <name> -- ls /workspaces/
如果仓库已存在,直接使用该路径。自动克隆的仓库反映默认分支,因此它并不包含你的本地工作——在运行任何东西之前,你必须先把本地工作同步过去。
选择覆盖你文件的最便宜的同步方式。 有两种方法,通常简单的那种就是正确的:
(a) 默认:传输工作树。 对于小型或中型仓库,直接复制磁盘上的文件。这会在一步之内捕获已跟踪的修改和未跟踪的文件,无需考虑提交或基线,也不会静默遗漏任何内容。直接上传少量文件;文件较多时对工作树打 tar 包:
bash
undefined

A few files - upload them directly.

A few files - upload them directly.

devbox upload <name> ./calc.go /workspaces/<repo-name>/calc.go --mkdir
devbox upload <name> ./calc.go /workspaces/<repo-name>/calc.go --mkdir

More than a handful - tar the tree, excluding .git and build output.

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) Large repo: align the commit, then patch.** Once the tree is big enough that copying it is slower than cloning it, let the devbox's own clone do the heavy lifting and send only a diff. This is strictly more machinery, so reach for it only when (a) is genuinely too slow.

**Important** The devbox clone is on the default branch, so the diff and the checkout MUST name the same commit or unrelated files get clobbered:

```bash
BASE=$(git merge-base origin/main HEAD)
git diff "$BASE" > /tmp/changes.patch   # add --binary if the diff touches generated/binary files
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 自己的克隆完成繁重工作,只发送一个 diff。这明显需要更多机制,所以只有在 (a) 确实太慢时才使用。

**重要** devbox 的克隆位于默认分支,因此 diff 和 checkout 必须指向同一个提交,否则不相关的文件会被覆盖:

```bash
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.

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

**Important (the failure mode that makes (b) risky)** `git diff` only covers TRACKED files. A brand-new file you have not `git add`ed is invisible to it, so a patch-based sync will quietly leave it behind - and if that file is a new test, you will confidently report a result from code that was never there. Requirement (b) is therefore incomplete on its own: send untracked files too.

```bash
git ls-files --others --exclude-standard    # exactly what a patch will MISS
Upload those directly, add them to the tarball, or rsync them if there are many:
bash
undefined
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` 只覆盖已跟踪(TRACKED)文件。一个你尚未 `git add` 的全新文件对它不可见,因此基于补丁的同步会悄悄漏掉它——而如果该文件是一个新测试,你会自信地报告一个从来不在那里的代码产生的结果。因此,(b) 本身是不完整的:也要发送未跟踪的文件。

```bash
git ls-files --others --exclude-standard    # exactly what a patch will MISS
直接上传这些文件、将其加入 tar 包,如果有大量文件则使用 rsync:
bash
undefined

for rsync - configure native ssh

for rsync - configure native ssh

devbox configure-ssh <name>
devbox configure-ssh <name>

After running this, you can connect with:

After running this, you can connect with:

ssh <name>.devbox.namespace
ssh <name>.devbox.namespace

Then list untracked files and feed them to rsync

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>/

**Verify before you trust a result.** Confirm the files you meant to send are actually there, so a sync gap surfaces now rather than as a wrong answer later:

```bash
devbox exec <name> -- ls -la /workspaces/<repo-name>
If the repo has no remote at all (a scratch or local-only repo), (b) is not available - use (a).
git ls-files --others --exclude-standard |
rsync -av --files-from=- .
<name>.devbox.namespace:/workspaces/<repo-name>/

**在信任结果之前先验证。** 确认你打算发送的文件确实存在,这样同步缺口会在当下暴露,而不是稍后变成一个错误答案:

```bash
devbox exec <name> -- ls -la /workspaces/<repo-name>
如果仓库根本没有 remote(临时仓库或仅本地仓库),则 (b) 不可用——使用 (a)。

Install toolchains

安装工具链

If a tool is missing, install only what the workload needs.
Important Check whether a tool is already present before installing it - on Linux,
builtin:default
ships more than you might expect, including languages such as Go. Try the command before reaching for a manual install.
Probe with the tool's own flag, which is a real executable:
bash
devbox exec <name> -- go version
command -v
will NOT work this way. It is a shell builtin, and
devbox exec
runs the command directly with no shell, so
devbox exec <name> -- command -v go
fails with
exec: "command": executable file not found in $PATH
- which looks like the tool is missing when it is not. If you want
command -v
, give it a shell:
bash
devbox exec <name> -- bash -lc 'command -v go >/dev/null && go version || echo MISSING_GO'
Important For every CLI tool the script uses, check if it exists first and install only if missing. Use platform-appropriate installers and artifacts. For example, on Linux/amd64:
bash
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
如果缺少某个工具,只安装工作负载需要的内容。
重要 在安装之前先检查工具是否已存在——在 Linux 上,
builtin:default
自带的工具可能比你预期的更多,包括 Go 等语言。先尝试该命令,再考虑手动安装。
使用工具自身的标志来探测,它是一个真实的可执行文件:
bash
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:
bash
devbox exec <name> -- bash -lc 'command -v go >/dev/null && go version || echo MISSING_GO'
重要 对于脚本使用的每个 CLI 工具,先检查它是否存在,仅在缺失时安装。使用适合平台的安装器和产物。例如,在 Linux/amd64 上:
bash
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. Run commands with
devbox exec

3. 用
devbox exec
运行命令

Important Run
devbox exec
invocations against different devboxes in parallel. Do NOT serialize independent work.
bash
devbox exec <name> -- <cmd> <args...>
devbox ssh <name>
remains available for interactive shells and TTY-dependent workflows. Prefer
devbox exec
for non-interactive commands.
Alternative: native ssh If a workflow uses a tool, which relies on standard SSH tooling (
scp
,
rsync
, etc.), run
devbox configure-ssh <name>
once to write an entry into your
~/.ssh/config
. After that, the devbox is reachable as
<name>.devbox.namespace
. Prefer
devbox exec
for commands; reach for native ssh when you specifically need standard tooling.
Important (exec does not give you a shell - but you can ask for one)
devbox exec
runs the command directly, so shell operators such as
&&
,
;
, redirections and variable expansion are NOT interpreted by default.
devbox exec <name> -- cd /src && make
will not do what you want.
Two ways to get multi-step work done, and they trade off differently:
Short multi-step work - invoke a shell explicitly. One round trip, and a mistake costs one re-run:
bash
devbox exec <name> -- bash -lc 'cd /workspaces/<repo-name> && go build ./... && go test ./...'
Longer or reusable logic - upload a script. Worth the extra round trips (
upload
,
chmod
, run) when the logic is long, needs careful quoting, or you want the exact steps recorded on the machine. Note that a bug in the script costs a re-upload AND a re-
chmod
, so prefer
bash -lc
while you are still iterating:
bash
devbox upload <name> /tmp/script.sh /tmp/script.sh
devbox exec   <name> -- chmod +x /tmp/script.sh
devbox exec   <name> -- bash /tmp/script.sh
Quoting is the thing to watch with
bash -lc
: wrap the whole program in single quotes and let the remote shell expand
$VARS
, or they will expand locally before the command ever leaves your machine.
重要 针对不同 devbox 的
devbox exec
调用请并行运行。不要将独立的工作串行化。
bash
devbox exec <name> -- <cmd> <args...>
devbox ssh <name>
仍可用于交互式 shell 和依赖 TTY 的工作流。非交互式命令优先使用
devbox exec
。
备选:原生 ssh 如果某个工作流使用的工具依赖标准 SSH 工具(
scp
、
rsync
等),运行一次
devbox configure-ssh <name>
,将条目写入你的
~/.ssh/config
。之后,devbox 可以通过
<name>.devbox.namespace
访问。命令优先使用
devbox exec
;当你确实需要标准工具时,再使用原生 ssh。
重要(exec 不会给你 shell——但你可以要求一个)
devbox exec
直接运行命令,因此
&&
、
;
、重定向和变量展开等 shell 运算符默认不会被解释。
devbox exec <name> -- cd /src && make
不会按你的预期工作。
有两种方式完成多步骤工作,它们的取舍不同:
较短的多步骤工作——显式调用 shell。 一次往返,出错只需重跑一次:
bash
devbox exec <name> -- bash -lc 'cd /workspaces/<repo-name> && go build ./... && go test ./...'
较长或可复用的逻辑——上传脚本。 当逻辑较长、需要小心引号,或你想在机器上记录确切步骤时,多花几次往返(
upload
、
chmod
、运行)是值得的。注意,脚本中的 bug 会同时导致重新上传和重新
chmod
,所以在迭代期间优先使用
bash -lc
:
bash
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
,否则它们在命令离开你的机器之前就会在本地展开。

Detached commands and retained logs

分离命令与保留日志

Use
devbox exec -d
for long-running commands. It starts the command, returns immediately, and prints an exec ID. Use that ID to stream retained and live output with
devbox logs
.
devbox logs list
shows previous executions and their status.
bash
devbox exec -d <name> -- <cmd> <args...>
对于长时间运行的命令,使用
devbox exec -d
。它会启动命令、立即返回,并打印一个 exec ID。使用该 ID 通过
devbox logs
流式查看保留的和实时的输出。
devbox logs list
显示之前的执行及其状态。
bash
devbox exec -d <name> -- <cmd> <args...>

exec_<id>

exec_<id>

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

**Important** Preflight every required CLI before `set -e` so a missing tool exits with a clear message rather than an opaque failure: `command -v <tool> >/dev/null || { echo "MISSING_TOOL: <tool>"; exit 127; }`. On exit 127 or a `MISSING_TOOL` marker, install the dependency and re-run - do NOT report the run as failed.

**Important** Write all script output to a remote log file and return only a tiny summary by default.

```bash
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
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` 标记时,安装依赖并重新运行——不要把这次运行报告为失败。

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

```bash
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.

Pull the full log only if the summary shows a non-zero exit.

devbox download <name> /workspaces/run.log /tmp/run.log

devbox download <name> /workspaces/run.log /tmp/run.log


**Note** Capture the workload's exit code (`status=0; cmd || status=$?`) before printing the summary. Use `devbox download` only for devboxes whose summary reported a non-zero exit, unless specified otherwise.

For test-runner-specific guidance (sharding, parallel runs, the hydrate-and-test recipe, result reporting), see [references/run-tests.md](references/run-tests.md).

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

有关测试运行器的具体指导(分片、并行运行、hydrate-and-test 配方、结果报告),请参阅 [references/run-tests.md](references/run-tests.md)。

4. Lifecycle

4. 生命周期

bash
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
bash
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

Keep a devbox alive through long-running work

让 devbox 在长时间运行的工作中保持存活

A devbox with an idle timeout auto-stops when nothing on it looks busy. The Devbox agent treats a running
devbox exec
or SSH command as busy for its whole runtime. Creating or connecting to a terminal session and receiving HTTP responses through an exposed
devbox.so
URL count only as recent activity for a bounded period. Work not covered by an active exec or SSH command needs an explicit marker:
bash
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
boxctl
is pre-installed on every devbox, so this works from your machine without installing anything on the box. From inside a devbox, drop the
devbox exec <name> --
prefix.
Mark anything that will run unattended outside an active
devbox exec
or SSH command: an overnight job started in a terminal session, a migration, a queue worker, or a dev server nobody is hitting yet. A foreground or detached
devbox exec
needs no marker while its command is still running. Without either form of activity the machine can stop mid-task and take the work with it.
Important Markers have no TTL and nothing cleans them up. One left behind holds the devbox awake and billed indefinitely, defeating the idle timeout entirely - so always pair a mark with the matching
clear-mark
, on failure paths too. Both commands are idempotent and exit 0 when the marker already exists or is already gone, which makes them safe in traps and retries. See references/inside-a-devbox.md for the trap pattern.
A marker only holds off the idle timeout.
devbox shutdown
and
devbox expire
still stop the machine regardless.
Important These
devbox url
commands require devbox CLI v0.0.182 or newer. Check with
devbox version
; if the installed version is older, run
devbox update
before using them.
Choose who can open
devbox.so
URLs
Each devbox has one access mode shared by all of its exposed URLs:
  • private
    - only the devbox owner.
  • workspace
    - members of the same Namespace workspace.
The URL mode initially follows the general devbox access mode, but is configured separately afterward. Changing URL access does not grant or remove SSH, exec, or file access to the devbox.
Inspect or change the Devbox-wide URL mode independently:
bash
devbox url access my-box -o json
devbox url access my-box --mode workspace -o json
Important
devbox url expose ... --access <mode>
changes this same Devbox-wide setting while exposing a port. It affects every existing and future exposed URL on that devbox; it does not set access only for the new URL. Per-URL access modes are not supported. If URLs need different audiences, ask before changing access or use a separate devbox.
Share web work with teammates When the user intends work running in a devbox to be reviewable by teammates, expose its port with
--access workspace
and return the resulting
devbox.so
URL. The URL remains available after the command exits. Pass
--name
when the port's purpose is known so the URL is easier to retrieve and remove later. Prefer JSON output for agent workflows.
Important (how to verify an exposed URL - and how not to) A successful
devbox url expose
that returns a URL IS your confirmation. Stop there and hand the URL to the user.
Do NOT try to fetch the URL to "prove" it works.
devbox.so
URLs are gated on a signed-in user session, which you do not have and cannot mint -
curl
will return
401 unauthorized
, and no API or ID token will change that. That
401
is not a failure and not evidence of anything you need. Chasing a
200
is the single most expensive dead end in this skill: it burns minutes on token endpoints and SSH tunnels to re-confirm a fact the CLI already gave you.
If you want to confirm the server is actually up before sharing, check it from inside the devbox, where no gateway auth applies:
bash
devbox exec <name> -- curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:<port>/
Bind servers to
0.0.0.0
, not
127.0.0.1
, or the
devbox.so
proxy cannot reach them.
bash
devbox url expose my-box --port 3000 --name web --access workspace -o json
If the user has not asked to share, omit
--access
and preserve the current mode. When sharing intent is unclear, inspect the mode and do not broaden access. If the user explicitly requires every exposed URL on the devbox to be owner-only, set
private
before exposing the new port:
bash
devbox url access my-box --mode private -o json
devbox url expose my-box --port 3000 --name web -o json
For local-only access or non-web services, use
devbox port-forward
. Example:
devbox port-forward my-box --ports 3000:3000,5432:5432
maps ports to
localhost:3000
and
localhost:5432
. The command blocks the terminal until Ctrl+C, so run it in a dedicated terminal or as a background process.
Whether and when to call
devbox expire
depends on the caller's intent - the test-suite workflow in references/run-tests.md tears down at the end; other use cases may keep the devbox alive.
Important On failure caused by missing dependencies, install them and retry the failing command. Do the same for any uploaded scripts.
带有空闲超时的 devbox 在没有任何忙碌迹象时会自动停止。Devbox agent 会将正在运行的
devbox exec
或 SSH 命令在整个运行期间视为忙碌。创建或连接到终端会话,以及通过暴露的
devbox.so
URL 接收 HTTP 响应,只算作有限时间内的近期活动。不受活动 exec 或 SSH 命令覆盖的工作需要显式标记:
bash
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
boxctl
预装在每个 devbox 上,因此你可以从自己的机器上直接使用,无需在 box 上安装任何东西。如果在 devbox 内部,去掉
devbox exec <name> --
前缀即可。
请为任何将在活动
devbox exec
或 SSH 命令之外无人值守运行的内容打上标记:在终端会话中启动的过夜任务、迁移、队列 worker,或还没有人访问的 dev 服务器。前台的或分离的
devbox exec
在其命令仍在运行时不需要标记。如果没有这两种活动形式中的任何一种,机器可能会在任务中途停止,并连带丢失工作。
重要 标记没有 TTL,也没有任何东西会清理它们。遗留的标记会让 devbox 无限期保持唤醒并计费,完全破坏空闲超时——所以始终将标记与对应的
clear-mark
配对,在失败路径上也是如此。这两个命令都是幂等的,当标记已存在或已消失时都会以 0 退出,因此在 trap 和重试中使用是安全的。trap 模式见 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 workspace 的成员。
URL 模式最初遵循常规的 devbox 访问模式,但之后会单独配置。更改 URL 访问权限并不会授予或撤销对 devbox 的 SSH、exec 或文件访问权限。
独立检查或更改 Devbox 全局的 URL 模式:
bash
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 token 都不会改变这一点。这个
401
不是失败,也不是你需要处理的证据。追逐
200
是此 skill 中最昂贵的死胡同:它会浪费几分钟在 token 端点和 SSH 隧道上,只为重新确认 CLI 已经告诉过你的事实。
如果你想在共享之前确认 服务器 确实已启动,请在 devbox 内部检查,那里不适用网关认证:
bash
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
代理无法访问它们。
bash
devbox url expose my-box --port 3000 --name web --access workspace -o json
如果用户没有要求共享,则省略
--access
并保留当前模式。当共享意图不明确时,检查模式且不要扩大访问范围。如果用户明确要求 devbox 上每个暴露的 URL 都仅限所有者,请在暴露新端口前设置
private
:
bash
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;其他用例可能会让 devbox 保持存活。
重要 对于因缺少依赖而导致的失败,请安装依赖并重试失败的命令。对任何上传的脚本也做同样处理。