> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mesa.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Sprites

> Use Mesa with Sprites sandboxes for stateful, high-performance agent workflows.

[Sprites](https://sprites.dev/) (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, pass the token in as `MESA_ACCESS_TOKEN`, and run `mesa mount --daemonize`.
3. **Run your agent** — `cd` into the mount path and launch your agent (ex. 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](/content/mesafs/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 `&&`.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { SpritesClient } from "@fly/sprites";
  import { Mesa } from "@mesadev/sdk";

  const mesa = new Mesa({ privateKey: process.env.MESA_PRIVATE_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 private key with no network call — your private key never enters the sandbox.
  const { token } = await mesa.tokens.create({
    authors: [{ name: "Sandbox Agent", email: "agent@example.com" }],
    scopes: ["read", "write"],
    repos: ["my-org/agent-workspace"],
    ttl_seconds: 60 * 60, // 1 hour; max 4 hours
  });

  // --- 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 -s -- --version 0.46.0",
      "sed -i 's/^#user_allow_other/user_allow_other/' /etc/fuse.conf",
      "chmod 666 /dev/fuse",
    ].join(" && "),
  ]);

  // Start Mesa as a background daemon with the short-lived token.
  await sprite.execFile("sh", [
    "-c",
    `MESA_ACCESS_TOKEN=${token} mesa mount --daemonize`,
  ]);

  // --- Run your agent ---

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

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

  ```python Python theme={null}
  import os
  from mesa_sdk import Mesa

  # --- Outside the sandbox: set up Mesa resources ---
  mesa = Mesa(private_key=os.environ["MESA_PRIVATE_KEY"])

  # Create a repo (or use an existing one)
  repo = await mesa.repos.create(name="agent-workspace")

  # Sign a scoped, self-expiring access token for the sandbox. Signed locally
  # from your private key with no network call — your private key never enters the sandbox.
  minted = await mesa.tokens.create(
      authors=[{"name": "Sandbox Agent", "email": "agent@example.com"}],
      scopes=["read", "write"],
      repos=["my-org/agent-workspace"],
      ttl_seconds=60 * 60,  # 1 hour; max 4 hours
  )

  # --- Inside the sandbox: run these with your Sprites command runner ---
  # Install the Mesa CLI.
  # Sprites exposes /dev/fuse as root-only by default, so we also fix permissions.
  install_cmd = "curl -fsSL https://mesa.dev/install.sh | sh -s -- --version 0.46.0 && sed -i 's/^#user_allow_other/user_allow_other/' /etc/fuse.conf && chmod 666 /dev/fuse"

  # Start Mesa as a background daemon with the short-lived token.
  mount_cmd = f"MESA_ACCESS_TOKEN={minted.token} mesa mount --daemonize"

  # --- Run your agent ---
  agent_cmd = 'cd ~/.local/share/mesa/mnt/my-org/agent-workspace && claude -p "Implement the feature described in TODO.md"'
  ```

  ```bash CLI theme={null}
  # Install the Mesa CLI.
  # Sprites exposes /dev/fuse as root-only by default, so we also fix permissions.
  curl -fsSL https://mesa.dev/install.sh | sh -s -- --version 0.46.0
  sed -i 's/^#user_allow_other/user_allow_other/' /etc/fuse.conf
  chmod 666 /dev/fuse

  # Start Mesa as a background daemon.
  MESA_ACCESS_TOKEN="$MESA_ACCESS_TOKEN" mesa mount --daemonize

  # --- Run your agent ---
  cd ~/.local/share/mesa/mnt/my-org/agent-workspace
  claude -p "Implement the feature described in TODO.md"
  ```
</CodeGroup>

## Tips

* **Use scoped, short-lived access tokens.** Sign a dedicated token for each sandbox session with only the scopes it needs. It's signed locally with your private key (which never enters the sandbox) and expires on its own. See [Authentication](/content/concepts/authentication) for details.
* **Pick a TTL that covers the session.** Tokens default to a 15 minute TTL and max out at 4 hours, and a mount keeps the token it started with for its whole lifetime. If the token expires mid-session, filesystem operations in the sprite start failing with authentication errors; mint a fresh token on the host and remount.
* **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](/content/mesafs/posix-mount#allow_other-and-user_allow_other) for the most common setup issue in sandbox environments.
* **Sprites are stateful.** Unlike ephemeral sandboxes, Sprites persist state across connections. The Mesa install survives a stop and resume, but the mount does not: mint a fresh token on the host and re-run `mesa mount --daemonize` after resuming.
