Remove Sprites sandbox provider

Drop the Sprites (Fly.io microVM) sandbox provider entirely. Three
providers remain: Local, Docker, and Daytona.

- Delete lib/crates/fabro-sandbox/src/sprites/ module
- Remove sprites feature flag and dep comments from Cargo.toml
- Remove sprites module declaration from lib.rs
- Update resolve_path cfg guard to daytona-only
- Delete docs/integrations/sprites.mdx and remove nav entry
- Remove Sprites rows from provider tables in docs
- Clean up SDK reference and changelog mentions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-30 12:23:06 -04:00
parent 3936f185cf
commit 73cbcabf77
11 changed files with 6 additions and 1379 deletions

View file

@ -29,10 +29,8 @@ Which source files affect which doc pages. Use this as guidance — also apply j
| `lib/crates/fabro-agent/src/subagent.rs` | `docs/agents/subagents.mdx` |
| `lib/crates/fabro-agent/src/mcp_integration.rs` | `docs/agents/mcp.mdx` |
| `lib/crates/fabro-llm/src/catalog.rs`, `lib/crates/fabro-llm/src/providers/*.rs` | `docs/core-concepts/models.mdx` |
| `lib/crates/fabro-exe/src/*.rs` | `docs/integrations/exe-dev.mdx`, `docs/execution/environments.mdx` |
| `lib/crates/fabro-devcontainer/src/*.rs` | `docs/execution/devcontainers.mdx` |
| `lib/crates/fabro-slack/src/*.rs` | `docs/integrations/slack.mdx` |
| `lib/crates/fabro-sprites/src/*.rs` | `docs/integrations/sprites.mdx` |
| `lib/crates/fabro-mcp/src/*.rs` | `docs/agents/mcp.mdx` |
| `lib/crates/fabro-api/src/*.rs` | `docs/api-reference/overview.mdx`, `docs/api-reference/demo-mode.mdx` |
| `lib/crates/fabro-api/src/server_config.rs` | `docs/administration/server-configuration.mdx` |

View file

@ -18,11 +18,11 @@ fabro llm chat --server-url http://localhost:3000
Fabro now supports three sandbox environments for running agent stages. In addition to Daytona, you can now use **exe.dev** VMs or **Sprites** (powered by Fly.io).
exe.dev (beta) manages ephemeral VMs through SSH with separate management and data plane connections. Sprites uses the `sprite` CLI to provision Fly.io VMs with full sandbox lifecycle support.
Daytona provides cloud sandbox VMs with full lifecycle support.
```toml title="run.toml"
[execution]
environment = "exe" # or "sprites" or "daytona"
environment = "daytona"
```
## Sandbox environment variables

View file

@ -74,9 +74,6 @@ Node handlers execute tools (bash commands, file edits) inside a **sandbox**. Fa
| `local` | Tools run directly on the host machine (default) |
| `docker` | Tools run inside a Docker container |
| `daytona` | Tools run in a cloud VM with SSH access |
| `ssh` | Tools run on any existing SSH host |
| `exe` | Tools run in a fast ephemeral VM from [exe.dev](https://exe.dev) |
| `sprites` | Tools run in a persistent VM from [Sprites](https://sprites.dev) |
The sandbox is configured per-run via CLI flags (`--sandbox docker`) or the run config TOML. See [Environments](/execution/environments) for details on each provider.

View file

@ -94,7 +94,6 @@
"integrations/github",
"integrations/daytona",
"integrations/slack",
"integrations/sprites",
"integrations/brave-search"
]
},

View file

@ -1,64 +0,0 @@
---
title: "Sprites (preview)"
description: "Run Fabro workflows in persistent Sprites VMs from Fly.io"
---
<Warning>
The Sprites sandbox provider is **in progress** and not yet available for use. This page describes the planned integration. We'll update it when Sprites support ships.
</Warning>
[Sprites](https://sprites.dev) (by Fly.io) provides persistent, hardware-isolated Linux microVMs for Fabro workflows. Unlike ephemeral providers, Sprites VMs persist across runs with auto-sleep/wake — so dependencies stay installed and caches stay warm.
## How it works
- Each run creates (or reuses) a Sprite VM via the `sprite` CLI
- Agent tool calls (shell commands, file edits, grep, glob) execute via `sprite exec` inside the VM
- The working directory is `/home/sprite`
- Each Sprite has a preview URL (e.g. `https://<name>-<org>.sprites.app/`)
- VMs auto-sleep after inactivity and wake on the next command
- Pre-installed toolchains include ripgrep
## Configuration
```bash
fabro run workflow.fabro --sandbox sprites
```
```toml title="run.toml"
[sandbox]
provider = "sprites"
```
A full configuration example with all Sprites-specific options:
```toml title="run.toml"
[sandbox]
provider = "sprites"
[sandbox.sprites]
org = "my-org"
url_auth = "public"
sprite_name = "my-existing-sprite"
```
| Option | Description |
|---|---|
| `org` | Sprites organization name (passed as `--org` to the CLI) |
| `url_auth` | Preview URL auth mode: `"public"` or `"sprite"` (default) |
| `sprite_name` | Reuse an existing Sprite instead of creating a new one. Skips create and destroy — useful for development |
## Prerequisites
- The `sprite` CLI installed and authenticated (`sprite login`)
- A `SPRITE_TOKEN` environment variable (or interactive login)
## Reusing Sprites
Set `sprite_name` to reuse an existing Sprite across runs. When set, Fabro skips creation and destruction — the Sprite persists between runs with its filesystem intact:
```toml title="run.toml"
[sandbox.sprites]
sprite_name = "my-dev-sprite"
```
This is useful for development workflows where you want to keep installed dependencies and project state between runs.

View file

@ -155,7 +155,7 @@ pub trait Sandbox: Send + Sync {
| `DockerSandbox` | Runs inside a Docker container (feature-gated: `docker`). |
| `ReadBeforeWriteSandbox` | Decorator that blocks writes to files the agent hasn't read. Wraps any `Arc<dyn Sandbox>`. |
External crates provide additional implementations: `ExeSandbox` (SSH-based) in `fabro-exe`, and `SpritesSandbox` in `fabro-sprites`.
The `DaytonaSandbox` implementation (feature-gated: `daytona`) runs inside a Daytona cloud sandbox.
### Provider profiles

View file

@ -10,7 +10,6 @@ description = "Sandbox trait and implementations for Fabro agent execution envir
default = ["local"]
local = []
docker = ["dep:bollard", "dep:tar", "dep:futures"]
sprites = ["dep:chrono", "dep:rand"]
daytona = ["dep:daytona-sdk", "dep:daytona-api-client", "dep:git2", "dep:fabro-github", "dep:fabro-config", "dep:chrono", "dep:rand"]
test-support = []
@ -44,11 +43,9 @@ fabro-config = { path = "../fabro-config", optional = true }
fabro-github = { path = "../fabro-github", optional = true }
fabro-types = { path = "../fabro-types" }
# sprites
# daytona
chrono = { workspace = true, optional = true }
rand = { workspace = true, optional = true }
# daytona
daytona-sdk = { workspace = true, optional = true }
daytona-api-client = { workspace = true, optional = true }
git2 = { workspace = true, optional = true }

View file

@ -16,9 +16,6 @@ pub mod local;
#[cfg(feature = "docker")]
pub mod docker;
#[cfg(feature = "sprites")]
pub mod sprites;
#[cfg(feature = "daytona")]
pub mod daytona;

View file

@ -501,8 +501,8 @@ pub trait Sandbox: Send + Sync {
}
/// Resolve a path: relative paths are prepended with the working directory.
/// Used by feature-gated sandbox implementations (exe, ssh, sprites, daytona).
#[cfg(any(feature = "sprites", feature = "daytona"))]
/// Used by the Daytona sandbox implementation.
#[cfg(feature = "daytona")]
pub(crate) fn resolve_path(path: &str, working_dir: &str) -> String {
if std::path::Path::new(path).is_absolute() {
path.to_string()

View file

@ -1,41 +0,0 @@
use async_trait::async_trait;
use super::{SpriteOutput, SpriteRunner};
/// Real implementation that invokes the `sprite` CLI binary.
#[derive(Default)]
pub struct CliSpriteRunner;
impl CliSpriteRunner {
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl SpriteRunner for CliSpriteRunner {
async fn run(&self, args: &[&str]) -> Result<SpriteOutput, String> {
let output = tokio::process::Command::new("sprite")
.args(args)
.output()
.await
.map_err(|e| format!("Failed to run sprite command: {e}"))?;
Ok(SpriteOutput {
stdout: String::from_utf8_lossy(&output.stdout).to_string(),
stderr: String::from_utf8_lossy(&output.stderr).to_string(),
exit_code: output.status.code().unwrap_or(-1),
})
}
async fn run_with_timeout(
&self,
args: &[&str],
timeout: std::time::Duration,
) -> Result<SpriteOutput, String> {
match tokio::time::timeout(timeout, self.run(args)).await {
Ok(result) => result,
Err(_) => Err("Command timed out".to_string()),
}
}
}

File diff suppressed because it is too large Load diff