adrs: boxd as an agent-computer substrate - #718
Conversation
Human-written suggestion per CONTRIBUTING.md. A ready implementation
(SANDBOX_BACKEND=boxd plus first-class "sandbox": { "backend": "boxd" })
lives on MichielMAnalytics/qm@boxd-sandbox for the maintainers to pull
from if aligned.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018SM8fz3TWnQCXXGEwDpHA4
Adds a boxd (boxd.sh) sandbox backend next to sprites and smolmachines,
driven by the official @boxd-sh/sdk over gRPC. One persistent microVM per
scope, resident disk, process sessions, backup and blob staging through the
shared exec helpers.
Behaviour pinned against the production cluster:
- machines are addressed by id (name lookups 404 on get/exec/upload for both
session tokens and API keys); the name→id map is a cache in front of
`machines.list({org?})`, so a fresh core instance re-derives it
- exec runs `timeout N sh -c …` via the agent's `/bin/sh -c`; exit codes are
exact, streamed output is unbounded, guest timeout reports 124
- uploads are server-side atomic (tmp + mv, parents created); reads stat
first, then download up to 3 MiB and `dd | base64` chunks above the 4 MiB
gRPC message cap
- suspended/hibernated machines wake on exec; stopped/failed ones get
`start` and a poll to running (~12 s); a ConflictError naming a stopped
machine is the only exec error retried, and only because it is raised
before the command runs
- `restartComputer` reboots and waits; `teardown({destroy})` deletes; scratch
boxes live under a separate name and are deleted at release
Env: BOXD_API_KEY (required), BOXD_BASE_URL, BOXD_ORG, BOXD_NAME_PREFIX,
BOXD_VCPU, BOXD_DISK_GB, BOXD_EGRESS_PROXY_URL, SANDBOX_TIMEOUT_SEC.
The three remote backends now share one options spread in wiring and one
table-driven branch in the dev-instance sandbox resolver instead of three
copies. `npm run smoke:boxd-sandbox` exercises the backend against a live
cluster.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018SM8fz3TWnQCXXGEwDpHA4
`qm.config.jsonc` now accepts `"sandbox": { "backend": "boxd" }` on every
hosting target (docker, fly, aws), alongside `local`, `sprites` and `aws`.
Until now boxd (like smolmachines) was reachable only through
`env.core.SANDBOX_BACKEND`, which the secrets catalog and the check gate
did not understand.
What "first-class" changes:
- validation: boxd is accepted everywhere and rejects the Fly layer-image
settings (`app`, `image`, `baseImage`, `env`, `secretEnv`), the same way
the aws substrate does, because nothing delivers them to a boxd machine
- `sandboxCoreEnv` renders `SANDBOX_BACKEND=boxd`, and the AWS renderer
gets a boxd branch instead of falling into the Lambda MicroVM default
- `check` no longer demands `sandbox.app` on docker/fly for boxd
- the secrets catalog sees a declared `sandbox.backend` on every target
(before, only the aws target consulted it), so `BOXD_API_KEY` is
required exactly when boxd is declared and an explicit `sprites` now
requires `SPRITES_TOKEN` on docker/fly too; the Fly sandbox token is
demanded only when a Fly deployment actually runs Sprites
- `sandbox publish` refuses a boxd deployment before any docker work,
on all three providers, with a message that says what to do instead
- derived Fly tomls drop the template's `FLY_SANDBOX_APP_NAME` /
`FLY_BASE_IMAGE` when the stack does not provide them (registered as
core stack keys); the checked-in acme toml is unchanged
- scaffold comments and the deploy-directory docs mention the option
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018SM8fz3TWnQCXXGEwDpHA4
|
Thanks for this, @MichielMAnalytics — and sorry for the slow response. We're closing this PR. Per We don't want your idea to get lost, so we've captured it in #722 to triage on our side. Please feel free to open an |
|
thanks @time-attack, fair enough opened the note as #859, just the adrs file in my own words. the tested implementation stays on my fork if it helps when you pick it up: main...MichielMAnalytics:qm:boxd-sandbox happy to co-author or answer anything on the boxd side |
adrs/boxd-sandbox.mdis Michiel's (co-founder, boxd.sh) own words, per CONTRIBUTING.md. The implementation is included in this PR as the two commits after it, so it can be merged as-is or pulled apart if you'd rather implement it your way.What it adds
SANDBOX_BACKEND=boxd: a durable per-scope agent computer on boxd microVMs via@boxd-sh/sdk(gRPC). Resident disk, process sessions, backup and blob staging through the existing exec helpers. Machines are addressed by id; reads above the 4 MiB gRPC cap are chunked; stopped machines are started, suspended/hibernated ones wake on exec."sandbox": { "backend": "boxd" }as a first-class deploy-config value on docker, fly and aws: validation,check, the secrets catalog (BOXD_API_KEY), env rendering andsandbox publishall know it.npm run smoke:boxd-sandbox(live), dev instance--sandbox boxd.Verification: 27 backend unit tests against an in-process fake; CLI suite 529/529; full root suite green; typecheck/eslint/oxlint/knip clean; live smoke against production boxd; real
claude-opus-5turns through qm's orchestrator (execute/write/read on a boxd VM). Details are in the commit messages.🤖 Generated with Claude Code
https://claude.ai/code/session_018SM8fz3TWnQCXXGEwDpHA4