> ## 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.

# Freestyle

> Use Mesa with Freestyle when your AI needs a whole computer, not just a code runner.

[Freestyle](https://freestyle.sh/) provides performant ephemeral VMs that are full linux systems. Freestyle is ideal when you want to give your AI a whole computer, not just run code snippets.

This guide shows the full end-to-end flow: use the Mesa SDK outside the sandbox to set up resources, then use the Freestyle 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 (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](/content/mesafs/posix-mount).

## Setup

The example uses two environment variables:

```bash theme={null}
MESA_PRIVATE_KEY=your-mesa-private-key
FREESTYLE_API_KEY=your-freestyle-api-key
```

## Example Code

Freestyle sandboxes are Debian-based by default, so the standard Mesa install script works out of the box.

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

  const mesa = new Mesa({ privateKey: process.env.MESA_PRIVATE_KEY });
  const freestyle = new Freestyle({ apiKey: process.env.FREESTYLE_API_KEY });

  // --- 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 { vm } = await freestyle.vms.create();

  // Mesa's installer will install all its dependencies through your system's package manager.
  await vm.exec("curl -fsSL https://mesa.dev/install.sh | sh -s -- --version 0.46.0");

  // Enable non-root access to the FUSE mount and fix /dev/fuse permissions.
  await vm.exec(
    [
      "sed -i 's/^#user_allow_other/user_allow_other/' /etc/fuse.conf",
      "chmod 666 /dev/fuse",
    ].join(" && ")
  );

  // Start Mesa as a background daemon. We pass the short-lived token as
  // MESA_ACCESS_TOKEN, so the private key never enters the sandbox.
  await vm.exec(`MESA_ACCESS_TOKEN=${token} mesa mount --daemonize`);

  // --- Run your agent ---

  await vm.exec(
    'cd ~/.local/share/mesa/mnt/my-org/agent-workspace \
      && claude -p "Implement the feature described in TODO.md"'
  );
  ```

  ```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 Freestyle's Python command runner ---
  # Mesa's installer will install all its dependencies through your system's package manager.
  install_cmd = "curl -fsSL https://mesa.dev/install.sh | sh -s -- --version 0.46.0"

  # Enable non-root access to the FUSE mount and fix /dev/fuse permissions.
  fuse_cmd = "sed -i 's/^#user_allow_other/user_allow_other/' /etc/fuse.conf && chmod 666 /dev/fuse"

  # Start Mesa as a background daemon. We pass the short-lived token as
  # MESA_ACCESS_TOKEN, so the private key never enters the sandbox.
  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}
  # Mesa's installer will install all its dependencies through your system's package manager.
  curl -fsSL https://mesa.dev/install.sh | sh -s -- --version 0.46.0

  # Enable non-root access to the FUSE mount and fix /dev/fuse permissions.
  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

* **Mint the token outside the sandbox.** Sign a short-lived, scoped access token with your private key outside the VM and pass only that token as `MESA_ACCESS_TOKEN`. Your private key never crosses the sandbox boundary. 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 VM start failing with authentication errors; mint a fresh token on the host and remount.
* **Install Mesa ahead of time when startup time matters.** Installing at runtime is fine for a demo, but preinstalling Mesa and its dependencies makes VM startup faster and more predictable.
* **Always use `--daemonize`.** This keeps Mesa mounted while your shell or agent continues to run.
* **Don't forget `user_allow_other`.** See [POSIX Mount](/content/mesafs/posix-mount#allow_other-and-user_allow_other) for the most common FUSE setup issue in sandbox environments.
* **Expect mount paths to depend on the VM user.** In this example the VM runs as `root`, so Mesa mounts under `/root/.local/share/mesa/mnt`.
