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.