Skip to content

Disposable Build Sandbox on Sprites

llms.txt lists every page for an agent
Optional: hand this page to your coding agentThe steps work by hand too.
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`.

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.

PhaseActivityPoint
CreatespriteCreatespawn the sandbox
WarmspriteExecinstall the toolchain / prime caches (once)
CheckpointspriteCheckpointsnapshot the warm toolchain — the prepared pool
StagespriteWriteFilewrite the source in
BuildspriteExecproduce the artifact
CollectspriteReadFileread the artifact out
ResetspriteRestorerewind to the warm toolchain for the next build
DestroyspriteDestroythrow the box away

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" })]),
],
});

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.

Terminal window
cd examples/sprites-build-sandbox
npm install
chant emulator up
# ✓ fly: chant-mudflaps up on http://localhost:4280
# ✓ fly: chant-spritzer up on http://localhost:4290
export SPRITES_BASE_URL=http://localhost:4290
chant run build-sandbox
chant emulator down # stop both containers when done

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.

Drop the SPRITES_BASE_URL override and set a token. The Op and the code stay the same:

Terminal window
unset SPRITES_BASE_URL
export SPRITES_API_TOKEN=...
chant run build-sandbox

The endpoint resolves to real Sprites, and the build runs in a real Firecracker sandbox instead of the emulator’s scripted interpreter.

chant