Skip to main content
Daytona provides cloud-hosted sandbox VMs for Fabro workflows. Each run gets an ephemeral, isolated environment with its own filesystem, network, and compute resources — keeping your host machine clean and giving agents a reproducible workspace.

What the Daytona integration enables

FeatureHow it’s used
Sandboxed executionAgent tool calls (shell commands, file edits, grep, glob) run inside a cloud VM instead of on the host
SnapshotsPre-built environment images so each run starts with dependencies already installed
SSH accessConnect to a running sandbox for live debugging
Network controlsRestrict agent egress with block-all or CIDR-based allow lists
MCP sandbox transportRun MCP servers inside the sandbox — e.g., Playwright for browser automation

Prerequisites

  • A DAYTONA_API_KEY environment variable (get one from app.daytona.io)
  • GitHub access configured via the default token strategy or a GitHub App (required for private repository cloning and checkpoint pushing)

Configuration

Set the sandbox provider in your run config TOML or via CLI flag:
fabro run workflow.fabro --sandbox daytona
run.toml
[run.sandbox]
provider = "daytona"
A full configuration example with all Daytona-specific options:
run.toml
[run.sandbox]
provider = "daytona"
preserve = false

[run.sandbox.daytona]
auto_stop_interval = 60

[run.sandbox.daytona.labels]
project = "fabro"
env = "staging"
team = "platform"

[run.sandbox.daytona.snapshot]
name = "rust-dev"
cpu = 4
memory = "8GB"
disk = "20GB"
dockerfile = "FROM rust:1.85-slim-bookworm\nRUN apt-get update && apt-get install -y git ripgrep"
See Server Configuration for the full reference on all sandbox fields and server defaults.

Network access control

Control outbound network access with the network field. Three modes are available:
run.toml
# Full access (default)
[run.sandbox.daytona]
network = "allow_all"

# Block all egress
[run.sandbox.daytona]
network = "block"

# CIDR-based allow list
[run.sandbox.daytona]
network = { allow_list = ["208.80.154.232/32", "10.0.0.0/8"] }
Use "block" or a CIDR allow list when running untrusted or generated code to prevent agents from making arbitrary network requests.

Snapshots

Snapshots let you pre-build an environment image so each run starts with dependencies already installed rather than installing them in setup commands every time.
run.toml
[sandbox.daytona.snapshot]
name = "my-snapshot"
cpu = 4
memory = 8
disk = 20
dockerfile = "FROM node:20-slim\nRUN apt-get update && apt-get install -y git"
When a run starts with a snapshot configured, Fabro looks up the snapshot by name. If it doesn’t exist and a dockerfile is provided, Fabro creates it automatically and polls until it reaches Active state (up to 10 minutes). If the snapshot already exists, it’s reused immediately.
If a snapshot is configured by name but doesn’t exist and no dockerfile is provided, the run fails immediately. If no snapshot is configured at all, sandboxes are created from the daytona-medium snapshot which includes standard dev tools (git, etc.).

Private repositories

Fabro automatically clones the current repository into the sandbox at /home/daytona/workspace. Public repositories work without extra configuration. Private repositories require GitHub access. In token mode, Fabro uses the stored token directly. In app mode, Fabro uses short-lived Installation Access Tokens scoped to the specific repository. If the clone fails without GitHub access configured, Fabro suggests running the setup flow:
Git clone failed: ... If this is a private repository,
run `gh auth login` or `fabro install` to configure GitHub access.

SSH access

Connect to a running Daytona sandbox via SSH for live debugging:
fabro sandbox ssh <run-id>
This creates temporary SSH credentials (valid for 60 minutes) and connects directly. Use --print to print the SSH command instead of connecting, or --ttl to set the credential expiry.
To keep the sandbox alive after the run completes, pass --preserve-sandbox to fabro run.

Sandbox lifecycle

Each sandbox gets a unique timestamped name (e.g. fabro-20260307-143022-a3f2) and is created as ephemeral. By default, sandboxes are destroyed when the run finishes.

Preservation

To keep a sandbox alive for debugging:
fabro run workflow.fabro --sandbox daytona --preserve-sandbox
Or in the run config:
run.toml
[run.sandbox]
provider = "daytona"
preserve = true
When preserved, Fabro prints the sandbox name so you can find it in the Daytona dashboard.

Auto-stop

The auto_stop_interval setting tells Daytona to stop the sandbox after a period of inactivity, saving costs for preserved or long-running sandboxes:
run.toml
[run.sandbox.daytona]
auto_stop_interval = 30

Server defaults

When running via fabro server start, the server config at ~/.fabro/settings.toml can set default Daytona settings for all runs. Run config TOML values override server defaults. Labels are merged — run config labels win on key collisions. The network setting uses simple override (run config replaces the server default entirely). See Server Configuration for details.

Troubleshooting

”Failed to create Daytona sandbox”

The DAYTONA_API_KEY environment variable is missing or invalid. Store it with fabro secret set DAYTONA_API_KEY ... or export it in the server process environment, then check that it’s a valid key from app.daytona.io.

”Snapshot does not exist and no dockerfile provided”

The run config references a snapshot name that doesn’t exist on Daytona, and no dockerfile is provided to create it. Either create the snapshot manually in the Daytona dashboard or add a dockerfile field to [sandbox.daytona.snapshot].

”Timed out waiting for snapshot to become active”

Snapshot creation took longer than 10 minutes. This can happen with large Dockerfiles. Check the snapshot status in the Daytona dashboard — it may still be building. Subsequent runs will reuse the snapshot once it’s active.

Git clone fails for private repositories

See Private repositories above. You need a GitHub App configured and installed on the repository’s organization or account.

Stall watchdog kills the run

Long-running commands in Daytona sandboxes may trigger the 1800-second stall watchdog if they don’t produce events. For workflows with long-running operations, increase the stall_timeout in the workflow graph:
digraph Example {
    graph [stall_timeout="1200"]
}