Skip to main content
Sprites (by Fly.io) provides stateful, disposable sandboxes that work well with Mesa. This guide shows the full end-to-end flow: use the Mesa SDK outside the sandbox to set up resources, then use the Sprites SDK to configure and mount Mesa inside the sandbox. The general flow for any sandbox integration is:
  1. Outside the sandbox — use the Mesa SDK (TypeScript or Python) to create repos, sign a short-lived access token, and orchestrate your workflow.
  2. Inside the sandbox — install the mesa CLI, configure it with a short-lived access token, and run mesa mount --daemonize to mount your repos as local directories.
  3. Run your agentcd into the mount path and launch your agent (e.g. Claude Code, Codex, or a custom agent). Any file edits are automatically persisted back to Mesa.
For details on FUSE setup, system dependencies, and container configuration, see POSIX Mount.

Create and mount

Sprites are Debian-based, so the standard Mesa install script works directly. Use execFile("sh", ["-c", ...]) to run shell commands — the SDK’s exec() method splits on whitespace and doesn’t support pipes or &&.
import { SpritesClient } from "@fly/sprites";
import { Mesa } from "@mesadev/sdk";

const mesa = new Mesa({ apiKey: process.env.MESA_API_KEY });
const client = new SpritesClient(process.env.SPRITES_TOKEN);

// --- Outside the sandbox: set up Mesa resources ---

// Create a repo (or use an existing one)
const repo = await mesa.repos.create({ name: "agent-workspace" });

// Sign a scoped, self-expiring access token for the sandbox. Signed locally
// from your API key with no network call — your API key never enters the sandbox.
const { token } = await mesa.tokens.create({
  scopes: ["read", "write"],
  repos: ["my-org/agent-workspace"],
  ttl_seconds: 3600, // 1 hour
});

// --- Inside the sandbox: install and mount Mesa ---

const sprite = await client.createSprite("mesa-sandbox");

// Install the Mesa CLI.
// Sprites exposes /dev/fuse as root-only by default, so we also fix permissions.
await sprite.execFile("sh", [
  "-c",
  [
    "curl -fsSL https://mesa.dev/install.sh | sh",
    "sed -i 's/^#user_allow_other/user_allow_other/' /etc/fuse.conf",
    "chmod 666 /dev/fuse",
  ].join(" && "),
]);

// Start Mesa as a background daemon.
// MESA_ORG configures the org; MESA_API_KEY supplies the credential — here the
// short-lived token we signed above, so the raw API key never enters the sandbox.
await sprite.execFile("sh", [
  "-c",
  `MESA_ORG=my-org MESA_API_KEY=${token} mesa mount -d -y`,
]);

// --- Run your agent ---

await sprite.execFile("sh", [
  "-c",
  'cd ~/.local/share/mesa/mnt/my-org/agent-workspace \
    && claude "Implement the feature described in TODO.md"',
]);

// Clean up when done
await sprite.destroy();

Tips

  • Use execFile, not exec. The Sprites SDK’s exec() method naively splits the command string on whitespace, breaking shell features like pipes (|) and chaining (&&). Always use execFile("sh", ["-c", "your command"]) instead.
  • Use scoped, short-lived access tokens. Sign a dedicated token for each sandbox session with only the scopes it needs — it’s signed locally from your API key (which never enters the sandbox) and expires on its own. See Authentication for details.
  • Use --daemonize. Always run mesa mount --daemonize in sandbox environments so Mesa runs as a background process and doesn’t block your agent’s terminal.
  • Don’t forget user_allow_other. See POSIX Mount — this is the most common setup issue in sandbox environments.
  • Sprites are stateful. Unlike ephemeral sandboxes, Sprites persist state across connections. You can stop and resume a sprite without losing the Mesa mount — just re-run mesa mount --daemonize after resuming.