Sandboxes
How to add new sandbox execution providers
This guide explains how to add support for a new sandbox provider to Sesame.
Overview
Sandbox providers are responsible for:
- Creating workspaces - Setting up isolated environments
- Executing commands - Running agent CLIs and other tools
- Managing lifecycle - Starting, stopping, and cleaning up
Provider Interface
All providers implement the SandboxProvider interface:
interface SandboxProvider {
// Create a new sandbox for a task
create(options: CreateOptions): Promise<Sandbox>;
// Get an existing sandbox
get(id: string): Promise<Sandbox | null>;
// List all sandboxes
list(): Promise<Sandbox[]>;
// Clean up resources
cleanup(): Promise<void>;
}
interface Sandbox {
id: string;
workdir: string;
// Execute a command
exec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
// Stream command output
execStream(command: string, args: string[], options?: ExecOptions): AsyncIterable<string>;
// File operations
readFile(path: string): Promise<string>;
writeFile(path: string, content: string): Promise<void>;
// Lifecycle
start(): Promise<void>;
stop(): Promise<void>;
destroy(): Promise<void>;
}File Structure
Step 1: Create Provider Class
import { SandboxProvider, Sandbox, CreateOptions } from "../types";
export class MyProvider implements SandboxProvider {
private sandboxes = new Map<string, MySandbox>();
async create(options: CreateOptions): Promise<Sandbox> {
const id = options.taskId;
// Create the sandbox environment
const sandbox = new MySandbox(id, options);
await sandbox.initialize();
this.sandboxes.set(id, sandbox);
return sandbox;
}
async get(id: string): Promise<Sandbox | null> {
return this.sandboxes.get(id) ?? null;
}
async list(): Promise<Sandbox[]> {
return Array.from(this.sandboxes.values());
}
async cleanup(): Promise<void> {
for (const sandbox of this.sandboxes.values()) {
await sandbox.destroy();
}
this.sandboxes.clear();
}
}
class MySandbox implements Sandbox {
id: string;
workdir: string;
constructor(id: string, options: CreateOptions) {
this.id = id;
this.workdir = `/path/to/workdir/${id}`;
}
async initialize(): Promise<void> {
// Set up the sandbox environment
}
async exec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult> {
// Execute command and return result
const result = await this.runCommand(command, args, options);
return {
exitCode: result.exitCode,
stdout: result.stdout,
stderr: result.stderr,
};
}
async *execStream(command: string, args: string[], options?: ExecOptions): AsyncIterable<string> {
// Stream command output
const process = this.spawnCommand(command, args, options);
for await (const chunk of process.stdout) {
yield chunk.toString();
}
}
async readFile(path: string): Promise<string> {
// Read file from sandbox
}
async writeFile(path: string, content: string): Promise<void> {
// Write file to sandbox
}
async start(): Promise<void> {
// Start/resume sandbox
}
async stop(): Promise<void> {
// Pause sandbox
}
async destroy(): Promise<void> {
// Clean up sandbox resources
}
}Step 2: Register Provider
Add your provider to the factory in packages/sandbox/src/providers/index.ts:
import { MyProvider } from "./my-provider";
export function createProvider(type: string): SandboxProvider {
switch (type) {
case "local":
return new LocalProvider();
case "docker":
return new DockerProvider();
case "vercel":
return new VercelSandboxProvider();
case "my-provider":
return new MyProvider();
default:
throw new Error(`Unknown provider: ${type}`);
}
}Step 3: Add Configuration
Add environment variables for your provider:
export const config = {
sandbox: {
provider: process.env.SANDBOX_PROVIDER ?? "local",
// Add provider-specific config
myProvider: {
endpoint: process.env.MY_PROVIDER_ENDPOINT,
apiKey: process.env.MY_PROVIDER_API_KEY,
},
},
};Step 4: Add Documentation
Create documentation in docs/content/docs/sandbox/my-provider.mdx:
---
title: My Provider Sandbox
description: Run tasks using My Provider
icon: Cloud
---
## Overview
The My Provider sandbox runs tasks using My Provider's infrastructure.
## Configuration
\`\`\`bash
SANDBOX_PROVIDER=my-provider
MY_PROVIDER_ENDPOINT=https://api.myprovider.com
MY_PROVIDER_API_KEY=your-api-key
\`\`\`
## Features
- Feature 1
- Feature 2Provider Patterns
Cloud Provider
For cloud-based sandboxes, see the Vercel provider implementation at packages/sandbox/src/providers/vercel.ts:
import { Sandbox } from "@vercel/sandbox";
import { BaseSandboxProvider } from "./base";
export class VercelSandboxProvider extends BaseSandboxProvider {
private sandbox: Sandbox | null = null;
async init(): Promise<void> {
this.sandbox = await Sandbox.create({
runtime: "node24",
ports: [3000, 5173, 8080],
timeout: 3600000,
resources: { vcpus: 2 },
});
}
async run(command: string, args: string[]): Promise<CommandResult> {
const result = await this.sandbox.runCommand({
cmd: command,
args,
cwd: this.projectDir,
});
return {
success: result.exitCode === 0,
exitCode: result.exitCode,
stdout: await result.stdout(),
stderr: await result.stderr(),
};
}
}Key considerations for cloud providers:
- Async initialization: Cloud sandboxes require async setup
- Port declaration: Some providers (like Vercel) require ports upfront
- Remote file operations: Use SDK methods instead of shell commands when available
Container Provider
For container-based sandboxes (like Docker, Kubernetes):
class ContainerProvider implements SandboxProvider {
async create(options: CreateOptions): Promise<Sandbox> {
// Create container
const container = await docker.createContainer({
Image: "ghcr.io/jakejarvis/sesame-sandbox:latest",
Cmd: ["tail", "-f", "/dev/null"],
HostConfig: {
Binds: [`${options.workdir}:/workspace`],
},
});
await container.start();
return new ContainerSandbox(container);
}
}VM Provider
For VM-based sandboxes:
class VMProvider implements SandboxProvider {
async create(options: CreateOptions): Promise<Sandbox> {
// Create VM
const vm = await this.hypervisor.createVM({
image: "ubuntu-22.04",
cpu: 2,
memory: 4096,
});
await vm.start();
return new VMSandbox(vm);
}
}Testing
import { MyProvider } from "../providers/my-provider";
describe("MyProvider", () => {
let provider: MyProvider;
beforeEach(() => {
provider = new MyProvider();
});
afterEach(async () => {
await provider.cleanup();
});
it("creates sandbox", async () => {
const sandbox = await provider.create({
taskId: "test-task",
workdir: "/tmp/test",
});
expect(sandbox.id).toBe("test-task");
});
it("executes commands", async () => {
const sandbox = await provider.create({
taskId: "test-task",
workdir: "/tmp/test",
});
const result = await sandbox.exec("echo", ["hello"]);
expect(result.stdout).toContain("hello");
});
});Security Considerations
When implementing a sandbox provider, consider how it interacts with Sesame's sandbox security layer.
Sandbox Security Integration
Sesame's @anthropic-ai/sandbox-runtime integration provides OS-level restrictions on top of your provider's isolation. Your provider should:
-
Support the security wrapper: The task executor wraps agent processes with sandbox security. Ensure your
exec()andexecStream()methods work with this wrapper. -
Provide workdir correctly: Sandbox security allows writes to the
workdirpath. Ensure this is set correctly. -
Handle violations gracefully: If sandbox security blocks an operation, your provider should handle the resulting errors without crashing.
Provider Security Properties
Document your provider's security properties clearly:
/**
* MyProvider security properties:
* - Isolation: Container-level (Docker)
* - Network: Isolated by default, configurable
* - Filesystem: Bind-mounted workspace only
* - Works with sandbox security: Yes
*/
export class MyProvider implements SandboxProvider {
// ...
}Testing with Sandbox Security
Test your provider both with and without sandbox security enabled:
describe("MyProvider with sandbox security", () => {
beforeAll(() => {
process.env.SANDBOX_SECURITY_ENABLED = "true";
});
it("executes commands within restrictions", async () => {
// Test that commands work with filesystem restrictions
});
it("handles blocked network access", async () => {
// Test behavior when network is restricted
});
});Checklist
- Implemented SandboxProvider interface
- Implemented Sandbox interface
- Registered in provider factory
- Added configuration options
- Added documentation
- Added tests
- Handles errors gracefully
- Cleans up resources properly
- Works with sandbox security enabled
- Documents security properties