Disposable Build Sandbox on Sprites
Show the whole prompt
Read https://intentius.io/chant/tutorials/sprites-build-sandbox/.
In `examples/sprites-build-sandbox`, run `npm install` and `npx chant emulator up`, export `SPRITES_BASE_URL=http://localhost:4290`, and run `npx chant run build-sandbox --no-record`.
Show me the output and the artifact the build read out, then run `npx chant emulator down`.
Set no Sprites token.
Never deploy to a real cloud account or shared environment (with `chant run`, `chant components` or a platform's own CLI), approve (a pull request review, `chant approve` or `chant run approve`), override a policy denial (`chant approve policy-override`), or merge; never cut or publish a release (`chant release cut --yes` or `chant release publish`), push or delete a `ci/*` tag (`chant ci tick` pushes them), or change the value of an existing flag; never touch `.chant/allowed_signers` or `chant/lifecycle`.Optional: hand this page to your coding agent
Read https://intentius.io/chant/tutorials/sprites-build-sandbox/.In `examples/sprites-build-sandbox`, run `npm install` and `npx chant emulator up`, export `SPRITES_BASE_URL=http://localhost:4290`, and run `npx chant run build-sandbox --no-record`.Show me the output and the artifact the build read out, then run `npx chant emulator down`.Set no Sprites token.Never deploy to a real cloud account or shared environment (with `chant run`, `chant components` or a platform's own CLI), approve (a pull request review, `chant approve` or `chant run approve`), override a policy denial (`chant approve policy-override`), or merge; never cut or publish a release (`chant release cut --yes` or `chant release publish`), push or delete a `ci/*` tag (`chant ci tick` pushes them), or change the value of an existing flag; never touch `.chant/allowed_signers` or `chant/lifecycle`.The sprites-build-sandbox
example is a disposable build box on a Sprite, Fly.io’s
stateful, checkpointable sandbox. It warms a toolchain once, checkpoints it,
then builds from staged source and reads the artifact out. It then resets to the
warm checkpoint so the next build starts fast.
Two ideas do the work:
- the Sprite is the disposable box: create it, use it, throw it away;
- the checkpoint is the prepared pool: a warm toolchain you restore per build instead of re-installing.
The filesystem activities stage the source in and read the artifact out without
shelling I/O through spriteExec. Sprites are imperative and ephemeral, so this
lives in chant’s Op/activity layer without a build phase or serialized plan.
| Phase | Activity | Point |
|---|---|---|
| Create | spriteCreate | spawn the sandbox |
| Warm | spriteExec | install the toolchain / prime caches (once) |
| Checkpoint | spriteCheckpoint | snapshot the warm toolchain — the prepared pool |
| Stage | spriteWriteFile | write the source in |
| Build | spriteExec | produce the artifact |
| Collect | spriteReadFile | read the artifact out |
| Reset | spriteRestore | rewind to the warm toolchain for the next build |
| Destroy | spriteDestroy | throw the box away |
The op
Section titled “The op”ops/build-sandbox.op.ts is a pure activity sequence:
import { Op, phase } from "@intentius/chant/op";import { spriteCreate, spriteExec, spriteCheckpoint, spriteWriteFile, spriteReadFile, spriteRestore, spriteDestroy } from "@intentius/chant-lexicon-fly";
export default Op({ name: "build-sandbox", taskQueue: "sprites", phases: [ phase("Create", [spriteCreate({ name: "builder", image: "sprites/base:latest" })]), phase("Warm", [spriteExec({ id: "builder", cmd: "echo ready > /opt/toolchain" })]), phase("Checkpoint", [spriteCheckpoint({ id: "builder", comment: "toolchain-ready" })]), phase("Stage", [spriteWriteFile({ id: "builder", path: "/src/main.txt", content: "hello", mkdir: true })]), phase("Build", [spriteExec({ id: "builder", cmd: "cat /src/main.txt > /out/artifact.txt" })]), phase("Collect", [spriteReadFile({ id: "builder", path: "/out/artifact.txt" })]), phase("Reset", [spriteRestore({ id: "builder", comment: "toolchain-ready" })]), phase("Destroy", [spriteDestroy({ id: "builder" })]), ],});Run it
Section titled “Run it”chant emulator up starts the local Sprites emulator
(spritzer) in a container and prints its endpoint, http://localhost:4290.
Export that as SPRITES_BASE_URL and the sprite activities talk to the emulator
instead of the real Sprites API, so this needs Docker but no Sprites account and
no key. The image tag is pinned in
lexicons/fly/src/op/activities/emulator-images.ts. The fly lexicon ships two
emulators, so up also starts mudflaps (the Machines API fake), which this Op
does not use.
cd examples/sprites-build-sandboxnpm install
chant emulator up# ✓ fly: chant-mudflaps up on http://localhost:4280# ✓ fly: chant-spritzer up on http://localhost:4290export SPRITES_BASE_URL=http://localhost:4290
chant run build-sandbox
chant emulator down # stop both containers when doneThe prepared pool
Section titled “The prepared pool”Warming a toolchain (installing compilers, priming caches) is the slow part of
a build. spriteCheckpoint snapshots it once; spriteRestore rewinds to it in
seconds. In a real pool you keep the Sprite alive and restore the warm checkpoint
per build, so each build starts from the toolchain, not a cold install. This
example checkpoints, builds, then resets to the checkpoint to show the cycle.
fly-deploy-rollback uses the same
fast reset for rollback.
Real Sprites
Section titled “Real Sprites”Drop the SPRITES_BASE_URL override and set a token. The Op and the code stay
the same:
unset SPRITES_BASE_URLexport SPRITES_API_TOKEN=...chant run build-sandboxThe endpoint resolves to real Sprites, and the build runs in a real Firecracker sandbox instead of the emulator’s scripted interpreter.