How to Integrate the Daytona Connector for Full Linux Container Sandboxes in Flue

The Daytona connector adapts the official @daytona/sdk client to Flue's SandboxFactory interface, enabling agents to execute commands in fully isolated Linux containers instead of the default in-process Bash environment.

Integrating the Daytona connector for full Linux container sandboxes transforms how agents run code in the withastro/flue repository. This connector plugs into Flue's modular architecture to replace local execution with remote, full-OS Linux containers. By implementing the SandboxFactory contract defined in packages/sdk/src/sandbox.ts, the Daytona connector provides persistent sandboxes with package managers, network stacks, and the ability to mount custom volumes.

Architecture and Runtime Flow

Flue's connector system creates a clean abstraction between the agent logic and the execution environment. Understanding this flow helps you debug integration issues and optimize sandbox reuse.

The Connector Interface

The SandboxFactory type in packages/sdk/src/types.ts defines the contract that all sandbox connectors must fulfill. When you invoke flue run, the system creates a harness via init, which receives your factory and builds a SessionEnv through createSandboxSessionEnv in packages/sdk/src/sandbox.ts.

The Daytona connector implements this by wrapping an initialized Daytona sandbox inside a DaytonaSandboxApi class. This class fulfills the SandboxApi interface methods including readFile, writeFile, and exec. The connector specification lives in connectors/sandbox--daytona.md (lines 39-53), while the generated TypeScript implementation resides at connectors/daytona.ts or .flue/connectors/daytona.ts depending on your project layout.

Execution Delegation Chain

The runtime follows a strict delegation pattern to ensure isolation:

Agent code → init({ sandbox: daytona(sandbox) }) → createSandboxSessionEnv
→ SessionEnv methods delegate to Daytona SDK → Remote Linux container

This chain guarantees that every LLM tool invocation—whether shell commands, file reads, or file writes—executes inside the remote container rather than the host machine.

Installation and Configuration

Setting up the Daytona connector requires three components: the connector code itself, the SDK dependency, and valid API credentials.

Step 1: Generate the Connector

Use the Flue CLI to install the Daytona connector into your project:

flue add daytona --print

This command prints the installation script and writes the connector file to ./connectors/daytona.ts or ./.flue/connectors/daytona.ts. Reference the detailed guide in docs/connect-daytona.md for project-specific layout options.

Step 2: Install Dependencies

Add the Daytona SDK to your package.json as specified in connectors/sandbox--daytona.md:

npm install @daytona/sdk

Step 3: Configure Environment Variables

The connector expects runtime credentials via environment variables. Create an environment file containing:

  • DAYTONA_API_KEY – Required for authentication
  • DAYTONA_API_URL – Optional, for custom Daytona instances
  • DAYTONA_TARGET – Optional, to specify the target region

Load these using Flue's environment flag:

flue dev --env .env.local

# or

flue run --env production.env

Basic Implementation Example

Once configured, wire the connector into your agent by importing the daytona factory and passing a configured Daytona sandbox to init.

import type { FlueContext } from '@flue/sdk/client';
import { Daytona } from '@daytona/sdk';
import { daytona } from '../connectors/daytona'; // adjust path if using .flue/

export const triggers = { webhook: true };

export default async function ({ init, env }: FlueContext) {
  // Initialize the Daytona client with API credentials
  const client = new Daytona({ apiKey: env.DAYTONA_API_KEY });
  
  // Create a fresh Linux container (supports custom images, env vars, etc.)
  const sandbox = await client.create();
  
  // Initialize Flue harness with the Daytona-backed sandbox
  const harness = await init({
    sandbox: daytona(sandbox),
    model: 'anthropic/claude-sonnet-4-6',
  });
  
  // Execute commands inside the remote container
  const session = await harness.session();
  return await session.shell('uname -a');
}

This implementation runs uname -a inside a full Linux container managed by Daytona, returning the remote kernel information rather than host system details.

Advanced Usage: Persistent Sandbox Sessions

For workflows requiring setup persistence—such as cloning repositories or installing dependencies before running LLM tasks—reuse the same Daytona sandbox across multiple Flue sessions.

export default async function ({ init, payload, env }: FlueContext) {
  const client = new Daytona({ apiKey: env.DAYTONA_API_KEY });
  const sandbox = await client.create();

  // Setup phase: initialize environment
  const setupHarness = await init({ sandbox: daytona(sandbox) });
  const setupSession = await setupHarness.session();
  await setupSession.shell(`git clone ${payload.repo} /workspace/project`);
  await setupSession.shell('npm install', { cwd: '/workspace/project' });

  // Working phase: same sandbox, different working directory
  const workHarness = await init({
    id: 'project',
    sandbox: daytona(sandbox),
    cwd: '/workspace/project',
    model: 'anthropic/claude-sonnet-4-6',
  });
  const workSession = await workHarness.session();
  
  return await workSession.prompt(payload.prompt);
}

daytona(sandbox) creates a factory bound to that specific container instance. Passing the same sandbox object to multiple init calls maintains state between sessions while isolating execution from the host machine.

Key Source Files Reference

Understanding these files helps you debug integration issues and extend the connector:

Summary

  • Integration point: The SandboxFactory interface in packages/sdk/src/types.ts enables swapping the default Bash environment for remote containers.
  • Installation: Run flue add daytona --print to generate the connector, then install @daytona/sdk via npm.
  • Configuration: Provide DAYTONA_API_KEY through environment files loaded with flue run --env <file>.
  • Implementation: Wrap a Daytona sandbox with the daytona() factory and pass it to init({ sandbox: daytona(sandbox) }).
  • Persistence: Reuse the same Daytona sandbox instance across multiple init calls to maintain state between setup and execution phases.
  • Isolation: All file system and shell operations execute inside full Linux containers via the DaytonaSandboxApi class, ensuring complete environment isolation.

Frequently Asked Questions

How does the Daytona connector differ from Flue's default Bash environment?

The default environment runs commands in-process using the host machine's Bash shell, while the Daytona connector delegates execution to remote Linux containers. According to the withastro/flue source code, the default SessionEnv executes locally, whereas the Daytona implementation in connectors/daytona.ts routes all exec, readFile, and writeFile calls through the @daytona/sdk to isolated sandboxes with full OS capabilities, package managers, and network isolation.

Can I use custom Docker images with the Daytona connector?

Yes, you can specify custom images when creating the Daytona sandbox. When calling client.create(), pass image configuration options as supported by the Daytona SDK. The connector itself is image-agnostic—it simply requires a valid sandbox instance. Pre-install languages, mount volumes, or configure the container via the Daytona SDK before passing it to the daytona() factory in your Flue agent.

What environment variables are required to run the Daytona connector?

You must provide DAYTONA_API_KEY, with optional DAYTONA_API_URL and DAYTONA_TARGET for custom deployments. The connector reads these at runtime from the environment file specified via flue dev --env <file> or flue run --env <file>. Without DAYTONA_API_KEY, the @daytona/sdk client initialization fails, preventing sandbox creation.

Is sandbox persistence maintained across multiple agent invocations?

Persistence depends on whether you reuse the same Daytona sandbox instance. Creating a new client.create() call spins up a fresh container, while passing the same sandbox object to multiple init calls maintains state. The source code in packages/sdk/src/sandbox.ts shows that SessionEnv instances created from the same factory share the underlying sandbox connection, making them ideal for multi-step workflows requiring dependency installation or file persistence.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →