Sandboxes & filesystems

A sandbox is just
files + a shell.

The agent loop consumes one thing — a Workspace: a FileSystem paired with a CommandExecutor. Swap in a browser WebContainer, the real local OS, or a cloud microVM (E2B, Vercel, Daytona, Cloudflare) without touching agent code. Pair any filesystem with any executor via composeWorkspace.

The Workspace model

Everything in this page implements two small interfaces. query() only ever sees the combination.

interface FileSystem {
  readFile(path: string): Promise<string | null>
  readBinary(path: string): Promise<Uint8Array | null>
  writeFile(path: string, contents: string): Promise<void>
  writeBinary(path: string, data: Uint8Array): Promise<void>
  deleteFile(path: string): Promise<void>
  readdir(path: string): Promise<Array<{ name: string; isDir: boolean }> | null>
  mkdir(path: string): Promise<void>
}

interface CommandExecutor {
  exec(command: string, timeoutMs?: number, env?: Record<string, string>):
    Promise<{ output: string; exitCode: number }>
}

// A Sandbox is both, optionally rooted at a cwd:
interface Sandbox extends FileSystem, CommandExecutor {
  readonly cwd?: string
  init?(): Promise<void>     // some providers need explicit setup…
  dispose?(): Promise<void>   // …and teardown
}

composeWorkspace — mix any FS with any executor

Pair a persistent browser filesystem with a remote shell, or build a file-only agent with NoopCommandExecutor (which refuses to run commands). When a cwd is given it is authoritative: relative paths resolve against it before hitting the underlying FS; absolute paths pass through.

import { composeWorkspace, MemoryFileSystem, NoopCommandExecutor } from 'anyclaude-sdk'

// A file-only workspace (no shell) rooted at /home/user
const workspace = composeWorkspace(
  new MemoryFileSystem(),
  new NoopCommandExecutor(),
  '/home/user'
)

query({ prompt, workspace, llm })

Mental model. Tools like read_file/write_file/bash call straight through to the Workspace. Choosing a sandbox is choosing where those calls land — a browser tab, this machine, or a cloud VM.

Sandbox providers

Adapters wrap each provider's client structurally — there's no hard dependency on their SDKs, so you install only the one you use. All implement the same Sandbox interface.

WebContainerWorkspace — browser

Runs a real Node-like environment (the jsh shell) entirely in the browser tab via StackBlitz WebContainers. Peer dep: @webcontainer/api.

import { WebContainer } from '@webcontainer/api'
import { WebContainerWorkspace, query } from 'anyclaude-sdk'

const wc = await WebContainer.boot()
const workspace = new WebContainerWorkspace(wc)   // optional 2nd arg: cwd

query({ prompt, workspace, llm })

LocalSandbox — real OS (Node / Bun)

Drives the host machine's actual filesystem and shell, like Claude Code. Auto-detects the platform (Windows / macOS / Linux); cwd defaults to process.cwd(). On Windows it uses cmd.exe; elsewhere $SHELL / /bin/sh (override via shell / shellArgs). No peer dep.

import { LocalSandbox, query } from 'anyclaude-sdk'

const workspace = new LocalSandbox({ cwd: '/path/to/project' })
console.log(workspace.platform)   // 'windows' | 'mac' | 'linux'

// The agent's working directory is taken from the sandbox automatically.
for await (const msg of query({ prompt: 'add a CLI flag and run the tests', workspace, llm })) { /* … */ }

Cloud microVMs — E2B · Vercel · Daytona · Cloudflare

Each wraps the provider's sandbox client. Construct the provider's sandbox, then hand it to the adapter. Default cwd shown per provider.

Peer dep: e2b · default cwd /home/user.

import { Sandbox } from 'e2b'
import { E2BSandbox, query } from 'anyclaude-sdk'

const sbx = await Sandbox.create()
const workspace = new E2BSandbox(sbx)            // or new E2BSandbox(sbx, '/home/user')

query({ prompt, workspace, llm })

Peer dep: @vercel/sandbox · default cwd /vercel/sandbox.

import { Sandbox } from '@vercel/sandbox'
import { VercelSandbox, query } from 'anyclaude-sdk'

const sbx = await Sandbox.create()
const workspace = new VercelSandbox(sbx)

query({ prompt, workspace, llm })

Peer dep: @daytonaio/sdk · default cwd /home/daytona.

import { Daytona } from '@daytonaio/sdk'
import { DaytonaSandbox, query } from 'anyclaude-sdk'

const workspaceVm = await new Daytona().create()
const workspace = new DaytonaSandbox(workspaceVm)

query({ prompt, workspace, llm })

Peer dep: @cloudflare/sandbox · default cwd /workspace. Pairs well with Workers / Durable Objects.

import { getSandbox } from '@cloudflare/sandbox'
import { CloudflareSandbox, query } from 'anyclaude-sdk'

const sbx = getSandbox(env.Sandbox, 'session-id')
const workspace = new CloudflareSandbox(sbx)

query({ prompt, workspace, llm })

Each adapter also has a create*Sandbox(client, cwd?) factory (e.g. createE2BSandbox) if you prefer functions over new. The *ClientLike types are structural — anything matching the shape works, so you're never blocked on an exact SDK version.

Filesystems

When you don't need a full sandbox shell (e.g. a browser chat agent that only reads/writes files), pick a filesystem and pair it with NoopCommandExecutor — or with a remote executor — via composeWorkspace.

MemoryFileSystem

In-memory, ephemeral. Great for tests, demos, and stateless serverless runs. Zero deps.

DexieFileSystem

IndexedDB-backed, durable across reloads, queryable, with metadata. The recommended persistent browser FS. Peer dep: dexie.

OpfsFileSystem

Origin Private File System — native hierarchical handles, best for large binary files. No extra dep (browser API).

seedLinuxTree(fs)

Lay down a standard Linux FHS skeleton (/home, /tmp, …) so an agent feels at home. Exports LINUX_DIRS, DEFAULT_HOME.

import { DexieFileSystem, seedLinuxTree } from 'anyclaude-sdk'
import { composeWorkspace, NoopCommandExecutor } from 'anyclaude-sdk'

const fs = new DexieFileSystem()        // persists in IndexedDB
await seedLinuxTree(fs)                  // scaffold /home, /tmp, …
const workspace = composeWorkspace(fs, new NoopCommandExecutor(), '/home/user')

query({ prompt: 'create notes.md and list the home dir', workspace, llm })

Recipes — which to use

Full shell in-tab → WebContainer. Files-only, persistent → Dexie + Noop.

import { WebContainer } from '@webcontainer/api'
import { WebContainerWorkspace } from 'anyclaude-sdk'
const workspace = new WebContainerWorkspace(await WebContainer.boot())
query({ prompt, workspace, llm })

Real machine, real shell → LocalSandbox.

import { LocalSandbox } from 'anyclaude-sdk'
const workspace = new LocalSandbox({ cwd: process.cwd() })
query({ prompt, workspace, llm })

Isolated, disposable, long-lived → a cloud microVM (E2B shown). Also lets the agent loop run inside the VM for unbounded runtimes — see Deploy.

import { Sandbox } from 'e2b'
import { E2BSandbox } from 'anyclaude-sdk'
const workspace = new E2BSandbox(await Sandbox.create())
query({ prompt, workspace, llm })

Next: Tools the agent uses against the workspace, or the API reference.