How the Agent-Sandbox Separation Architecture Works in Open Agents

The agent-sandbox separation architecture in Open Agents isolates the decision-making logic (agent) from the execution environment (sandbox) through a generic interface, allowing the agent to run LLM loops while delegating file operations, command execution, and networking to an isolated Vercel Firecracker VM.

Open Agents by Vercel Labs implements a clean architectural boundary between the agent that reasons and plans, and the sandbox where code actually executes. This separation ensures security, enables persistence through snapshots, and keeps the agent core portable across different execution backends. The architecture relies on an abstract Sandbox interface that the agent consumes, while concrete implementations handle the actual isolation mechanics.

Core Components of the Architecture

The Agent Layer

The agent logic lives in packages/agent/open-harness-agent.ts and implements a ToolLoopAgent. This component is responsible for building system prompts, managing the LLM conversation loop, and deciding which tools to invoke. Crucially, the agent does not know it is running inside a Vercel VM—it only knows that it has access to a sandbox object passed via call options.

The prepareCall hook (lines 115-125) injects sandbox context—such as the working directory and current branch—into the system prompt. When the LLM decides to read a file, the agent invokes the read tool defined in packages/agent/tools/read.ts, which simply forwards the request to the sandbox interface.

The Sandbox Interface

The contract between agent and execution environment is defined in packages/sandbox/interface.ts. This file exports the abstract Sandbox type, along with supporting types like SandboxHooks, SandboxStatus, and SandboxState. The interface declares methods such as readFile, writeFile, exec, snapshot, and stop.

By programming against this interface, the agent remains backend-agnostic. The interface is re-exported through packages/sandbox/index.ts, which also exposes the connectSandbox factory function that dispatches to concrete implementations based on a type discriminator.

The Vercel Sandbox Implementation

The concrete implementation resides in packages/sandbox/vercel/sandbox.ts. This file implements the Sandbox interface using the @vercel/sandbox SDK, which orchestrates Firecracker microVMs. Key methods include:

  • create() (lines 93-146): Provisions a new VM with specified CPU, memory, and timeout.
  • connect() (lines 202-260): Reattaches to an existing sandbox using persisted state.
  • extendTimeout() (lines 325-349): Adds time to a running session.
  • snapshot() (lines 410-424): Captures disk state for later resumption.
  • stop() (lines 446-461): Terminates the VM.

The implementation handles credential brokering, port exposure for preview servers, and file system operations via the SDK.

How the Agent Communicates with the Sandbox

When the agent requires environmental interaction, it invokes a tool from packages/agent/tools/*.ts (e.g., read.ts, write.ts, bash.ts). Each tool receives the sandbox instance through the options.sandbox parameter injected during the agent call.

Data flow example:

  1. User code initializes the connection:

    import { openHarnessAgent } from "@open-harness/agent";
    import { connectVercelSandbox } from "@open-harness/sandbox";
    
    async function runExample() {
      const sandbox = await connectVercelSandbox({
        name: "demo-session",
        source: { url: "https://github.com/vercel/next.js", branch: "main" },
        timeout: 300_000,
        ports: [3000],
        githubToken: process.env.GITHUB_TOKEN,
      });
    
      const result = await openHarnessAgent.call({
        sandbox,
        model: "anthropic/claude-opus-4.6",
      });
    }
  2. Agent reasoning: Inside open-harness-agent.ts, the prepareCall hook builds a system prompt containing sandbox context (working directory, git branch).

  3. Tool invocation: When the LLM decides to read a file, the agent calls the read tool. The tool implementation in packages/agent/tools/read.ts forwards the call:

    async function readFileTool(sandbox: Sandbox, path: string) {
      return await sandbox.readFile(path, "utf-8");
    }
  4. Sandbox execution: The call reaches VercelSandbox.readFile (lines 662-672 of packages/sandbox/vercel/sandbox.ts), which uses the @vercel/sandbox SDK to fetch the file from the Firecracker VM.

  5. Response chain: The result flows back through the tool to the agent, then to the LLM as a conversation message.

Lifecycle Management and Persistence

The architecture supports long-running and resumable sessions through the factory pattern and state management.

Factory and Connection Logic

The packages/sandbox/factory.ts file exports connectSandbox(), which acts as a dispatcher. It inspects the type discriminator in the provided state or options (e.g., type: "vercel") and routes to the appropriate connector. For Vercel sandboxes, this delegates to packages/sandbox/vercel/connect.ts.

Reconnecting to Persisted Sessions

Sandboxes can be snapshotted and later resumed. The VercelSandbox.snapshot() method captures the VM disk state, while connect() reattaches to an existing session using persisted SandboxState.

import { connectSandbox } from "@open-harness/sandbox";
import { VercelState } from "@open-harness/sandbox";

async function reconnect(state: VercelState) {
  const sandbox = await connectSandbox({ state });
  // Continue work with the restored file system and running processes
}

Timeout Management

The Vercel implementation supports extending session timeouts via extendTimeout() (lines 325-349). This allows the agent to request additional compute time for long-running tasks without provisioning a new VM.

// Inside an agent tool or external controller
if ("extendTimeout" in sandbox) {
  await sandbox.extendTimeout(120_000); // Add 2 minutes
}

Key Implementation Files

File Role
packages/agent/open-harness-agent.ts Core ToolLoopAgent; receives sandbox in call options and injects context into prompts.
packages/agent/tools/read.ts Tool forwarding file read requests to the sandbox interface.
packages/agent/tools/write.ts Tool forwarding file write requests.
packages/agent/tools/bash.ts Tool forwarding command execution requests.
packages/sandbox/interface.ts Abstract Sandbox API definition (readFile, writeFile, exec, snapshot, etc.).
packages/sandbox/index.ts Public exports including connectSandbox factory.
packages/sandbox/factory.ts Dispatcher that routes to concrete implementations based on type discriminator.
packages/sandbox/vercel/sandbox.ts Vercel Firecracker VM implementation with lifecycle management.
packages/sandbox/vercel/connect.ts Connection helper for creating or resuming Vercel sandboxes.
packages/sandbox/vercel/config.ts Configuration types for the Vercel SDK.

Summary

  • Clean separation: The agent in packages/agent/open-harness-agent.ts operates solely against the abstract Sandbox interface defined in packages/sandbox/interface.ts, remaining agnostic to whether execution happens in a Firecracker VM, Docker container, or local subprocess.

  • Interface-driven design: Tools in packages/agent/tools/*.ts receive a sandbox instance via call options and forward operations (read, write, exec) to the interface methods, ensuring consistent error handling and resource management.

  • Vercel implementation: The concrete sandbox in packages/sandbox/vercel/sandbox.ts wraps the @vercel/sandbox SDK to provision Firecracker microVMs, supporting file system operations, command execution, port exposure, snapshotting, and timeout extension.

  • Factory routing: packages/sandbox/factory.ts dispatches to the correct implementation based on a type discriminator, enabling multi-backend support and seamless reconnection to persisted sessions via connectSandbox().

Frequently Asked Questions

What is the agent-sandbox separation architecture in Open Agents?

The agent-sandbox separation architecture is a design pattern used in the vercel-labs/open-agents repository that isolates the LLM reasoning logic (agent) from the code execution environment (sandbox). The agent, implemented in packages/agent/open-harness-agent.ts, makes decisions and calls tools, but all file operations, command execution, and network access are delegated to a sandbox object that implements the abstract Sandbox interface defined in packages/sandbox/interface.ts.

How does the agent access files in the sandbox?

The agent accesses files through thin tool wrappers located in packages/agent/tools/read.ts and packages/agent/tools/write.ts. When the LLM decides to read a file, the agent's readFileTool() function receives the sandbox instance from the call options and invokes sandbox.readFile(path, "utf-8"). This call travels through the abstract interface to the concrete implementation in packages/sandbox/vercel/sandbox.ts, which uses the @vercel/sandbox SDK to fetch the file from the Firecracker VM.

Can I use a different sandbox backend with Open Agents?

Yes, the architecture supports swapping sandbox backends without modifying agent code. The agent depends only on the abstract Sandbox interface in packages/sandbox/interface.ts, not on the Vercel-specific implementation. To add a new backend, implement the Sandbox interface in a new package (e.g., packages/sandbox/docker/), then update packages/sandbox/factory.ts to route to your implementation based on a new type discriminator. The connectSandbox() function will then return your custom sandbox when the corresponding state type is provided.

How does sandbox persistence and reconnection work?

The Vercel sandbox supports persistence through the snapshot() and connect() methods defined in packages/sandbox/vercel/sandbox.ts. When snapshot() is called, the current Firecracker VM state is captured and returned as a SandboxState object containing a unique identifier and metadata. To reconnect, pass this state to connectSandbox() in packages/sandbox/factory.ts, which detects the type:"vercel" discriminator and delegates to the connection logic in packages/sandbox/vercel/connect.ts. This reattaches to the existing VM, preserving the file system and any running processes.

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 →