Skip to main content

Fly.io Sprites

Executes commands in persistent Fly.io Sprites through the official @fly/sprites SDK. A Sprite is a Linux VM that keeps its filesystem between runs and hibernates on its own when idle. SpritesSandbox gets or creates a Sprite by name, so a new process can reconnect to the same files. Supports command execution with streaming output, timeouts, cancellation, background processes with stdin, and checkpoint capture. For interface details, see WorkspaceSandbox interface.

Installation
Direct link to Installation

npm install @mastra/sprites
note

@mastra/sprites requires Node.js 24 or later because the @fly/sprites SDK does.

Set your Sprites API token in one of three ways.

export SPRITES_TOKEN=your-api-token

Usage
Direct link to Usage

Add a SpritesSandbox to a workspace and assign it to an agent:

import { Agent } from '@mastra/core/agent'
import { Workspace } from '@mastra/core/workspace'
import { SpritesSandbox } from '@mastra/sprites'

const workspace = new Workspace({
sandbox: new SpritesSandbox({
id: 'mastra-project',
// token read from SPRITES_TOKEN
}),
})

const agent = new Agent({
id: 'code-agent',
name: 'Code Agent',
instructions: 'You are a coding assistant working in this workspace.',
model: 'anthropic/claude-sonnet-4-6',
workspace,
})

const response = await agent.generate(
'Print "Hello, world!" and show the current working directory.',
)

console.log(response.text)

Reusing a Sprite
Direct link to Reusing a Sprite

The id is the Sprite name. On start(), SpritesSandbox looks up a Sprite with that name and reconnects to it, or creates one when none exists. Files written in an earlier session are still there:

const first = new SpritesSandbox({ id: 'mastra-project' })
await first.executeCommand('sh', ['-c', 'echo hello > notes.txt'])
await first.stop()

// Later, possibly in another process
const second = new SpritesSandbox({ id: 'mastra-project' })
const result = await second.executeCommand('cat', ['notes.txt'])
console.log(result.stdout) // hello

Any existing Sprite with the same name in your account is adopted, so choose names that are unique to the project. When id is omitted, a random name is generated.

spriteConfig (RAM, CPUs, region, storage) is only applied when the Sprite is created.

Stopping and destroying
Direct link to Stopping and destroying

stop() and destroy() do different things:

  • stop() kills background processes started by this instance and closes the SDK connection. The Sprite and its filesystem are kept. Sprites hibernate on their own when idle, so there is nothing to suspend.
  • destroy() permanently deletes the Sprite and its filesystem. It works without calling start() first, and a Sprite that no longer exists is treated as already deleted.
const sandbox = new SpritesSandbox({ id: 'mastra-project' })

// Remove the Sprite when the project is finished
await sandbox.destroy()

Checkpoints
Direct link to Checkpoints

snapshot() captures a checkpoint of the Sprite's current state and waits for the capture to finish:

await sandbox.snapshot()

Checkpoints live inside the Sprite. They can't be used to boot or seed another sandbox, so supportsCheckpoints is false and SpritesSandbox doesn't implement clone(). Use the @fly/sprites SDK through sandbox.sprite to list or restore checkpoints.

Streaming output
Direct link to Streaming output

Pass onStdout and onStderr to receive output as it arrives:

await sandbox.executeCommand('npm', ['install'], {
onStdout: data => process.stdout.write(data),
onStderr: data => process.stderr.write(data),
timeout: 120_000,
})

When a command times out or its abortSignal fires, the command is killed and the result reports killed: true.

Constructor parameters
Direct link to Constructor parameters

id?:

string
= Auto-generated
Sprite name, also used as the sandbox ID. An existing Sprite with this name is reused; otherwise one is created.

token?:

string
= SPRITES_TOKEN environment variable
Sprites API token.

baseURL?:

string
= 'https://api.sprites.dev'
Sprites API base URL.

spriteConfig?:

SpriteConfig
Machine configuration (ramMB, cpus, region, storageGB). Only applied when the Sprite is created.

timeout?:

number
Default command timeout in milliseconds. A per-command timeout takes precedence.

env?:

Record<string, string>
Environment variables added to every command. Per-command env takes precedence.

workingDirectory?:

string
Default working directory for commands. Defaults to the Sprite user home directory.

instructions?:

string | (opts) => string
Override the default agent instructions. A string replaces them entirely; a function receives the default instructions and returns the final text.

Properties
Direct link to Properties

id:

string
Sprite name and sandbox identifier.

name:

string
Provider name ('SpritesSandbox').

provider:

string
Provider identifier ('sprites').

status:

ProviderStatus
Current lifecycle status of the sandbox.

sprite:

Sprite
The underlying @fly/sprites Sprite for direct SDK access. Throws SandboxNotReadyError if the sandbox has not been started.

processes:

SpritesProcessManager
Background process manager. See SandboxProcessManager reference.

Methods
Direct link to Methods

stop:

() => Promise<void>
Kill background processes and close the SDK connection. The Sprite and its filesystem are kept.

destroy:

() => Promise<void>
Permanently delete the Sprite. Works without a prior start.

snapshot:

() => Promise<void>
Capture a checkpoint of the Sprite. Throws if the capture fails.

Background processes
Direct link to Background processes

SpritesSandbox includes a process manager for spawning and managing background processes. Each process runs in its own Sprites exec session and supports stdin.

const sandbox = new SpritesSandbox({ id: 'mastra-project' })
await sandbox.start()

const handle = await sandbox.processes.spawn('node server.js', {
env: { PORT: '3000' },
onStdout: data => console.log(data),
})

await handle.sendStdin('reload\n')
await handle.kill()

Processes started by one SpritesSandbox instance are not visible to another instance, and stop() kills them.

See SandboxProcessManager reference for the full API.

Editor provider
Direct link to Editor provider

Register the provider with MastraEditor to hydrate stored sandbox configs into runtime instances:

import { MastraEditor } from '@mastra/editor'
import { spritesSandboxProvider } from '@mastra/sprites'

const editor = new MastraEditor({
sandboxes: { [spritesSandboxProvider.id]: spritesSandboxProvider },
})

See the Sandbox provider reference for details on registering custom sandbox providers.