Execute code in isolated, ephemeral containers with configurable runtimes, networking, and file access. The sandbox service is available via ctx.sandbox in agents and c.var.sandbox in routes.
Use the @agentuity/sandbox standalone package to access this service from any Node.js or Bun app without the runtime.
For patterns, one-shot vs interactive workflows, and snapshot configuration, see Sandbox SDK Usage.
run(options)
Execute a single command in a disposable sandbox. The sandbox is automatically created and destroyed after execution completes. Use this for stateless, one-shot tasks.
| Param | Type | Required | Description |
|---|---|---|---|
options | SandboxRunOptions | yes | Execution options (see below) |
SandboxRunOptions fields:
| Field | Type | Required | Description |
|---|---|---|---|
command | object | yes | { exec: string[], files?: FileToWrite[] } |
runtime | string | no | Runtime name (e.g., 'bun:1', 'python:3.14') |
runtimeId | string | no | Runtime ID (e.g., 'srt_xxx') |
name | string | no | Sandbox name |
description | string | no | Sandbox description |
resources | SandboxResources | no | CPU, memory, and disk limits |
env | Record<string, string> | no | Environment variables |
network | SandboxNetworkConfig | no | { enabled?: boolean, port?: number } |
timeout | SandboxTimeoutConfig | no | { idle?: string, execution?: string } |
snapshot | string | no | Snapshot ID or tag to restore from |
dependencies | string[] | no | Apt packages to install |
packages | string[] | no | npm/bun packages to install globally |
metadata | Record<string, unknown> | no | User-defined metadata |
Returns: Promise<SandboxRunResult>
interface SandboxRunResult {
sandboxId: string; // Sandbox ID
exitCode: number; // Process exit code
durationMs: number; // Execution time in milliseconds
stdout?: string; // Captured stdout
stderr?: string; // Captured stderr
}Example
import { createAgent } from '@agentuity/runtime';
import { z } from 'zod';
const agent = createAgent('CodeRunner', {
schema: {
input: z.object({ code: z.string() }),
output: z.object({ output: z.string(), exitCode: z.number() }),
},
handler: async (ctx, input) => {
const result = await ctx.sandbox.run({
runtime: 'bun:1',
command: {
exec: ['bun', 'run', 'script.ts'],
files: [
{ path: 'script.ts', content: Buffer.from(input.code) },
],
},
timeout: { execution: '30s' },
});
ctx.logger.info('Exit code: %d, duration: %dms', result.exitCode, result.durationMs);
return { output: result.stdout ?? '', exitCode: result.exitCode };
},
});create(options?)
Create an interactive sandbox that persists across multiple commands. Use this for multi-step workflows where you need to inspect state between commands.
| Param | Type | Required | Description |
|---|---|---|---|
options | SandboxCreateOptions | no | Creation options (see run() fields above, plus command and files) |
Additional fields beyond run() options:
| Field | Type | Description |
|---|---|---|
command | SandboxCommand | Initial command to execute, with optional mode: 'oneshot' | 'interactive' |
files | FileToWrite[] | Files to write to the workspace on creation |
Returns: Promise<Sandbox>
The Sandbox object provides methods for interacting with the running container:
interface Sandbox {
id: string;
status: string;
name?: string;
description?: string;
stdout: StreamReader; // Read-only stdout stream
stderr: StreamReader; // Read-only stderr stream
interleaved: boolean; // True if stdout/stderr share a stream
execute(options: ExecuteOptions): Promise<Execution>;
writeFiles(files: FileToWrite[]): Promise<void>;
readFile(path: string): Promise<ReadableStream<Uint8Array>>;
listFiles(path?: string): Promise<SandboxFileInfo[]>;
mkDir(path: string, recursive?: boolean): Promise<void>;
rmFile(path: string): Promise<void>;
rmDir(path: string, recursive?: boolean): Promise<void>;
setEnv(env: Record<string, string | null>): Promise<Record<string, string>>;
pause(): Promise<void>;
resume(): Promise<void>;
destroy(): Promise<void>;
}Example
const sandbox = await ctx.sandbox.create({
runtime: 'bun:1',
network: { enabled: true },
timeout: { idle: '10m' },
});
try {
// Write files and execute commands
await sandbox.writeFiles([
{ path: 'index.ts', content: Buffer.from('console.log("hello")') },
]);
const exec = await sandbox.execute({
command: ['bun', 'run', 'index.ts'],
});
ctx.logger.info('Exit code: %d', exec.exitCode);
} finally {
await sandbox.destroy();
}connect(sandboxId)
Get a full Sandbox instance for an existing sandbox by ID. Useful for reconnecting to a sandbox created earlier or in a different handler.
| Param | Type | Required | Description |
|---|---|---|---|
sandboxId | string | yes | Sandbox ID to connect to |
Returns: Promise<Sandbox>
Example
// Reconnect to a previously created sandbox
const sandbox = await ctx.sandbox.connect('sbx_abc123');
const files = await sandbox.listFiles('/home/agentuity');
ctx.logger.info('Found %d files', files.length);get(sandboxId)
Get sandbox metadata without creating a full interactive connection.
| Param | Type | Required | Description |
|---|---|---|---|
sandboxId | string | yes | Sandbox ID |
Returns: Promise<SandboxInfo> -- metadata including status, runtime, creation time, and resource configuration.
list(params?)
List sandboxes with optional filtering and pagination.
| Param | Type | Required | Description |
|---|---|---|---|
params | ListSandboxesParams | no | Pagination and filter options |
Returns: Promise<ListSandboxesResponse> with sandboxes array and total count.
destroy(sandboxId)
Permanently destroy a sandbox and release its resources.
| Param | Type | Required | Description |
|---|---|---|---|
sandboxId | string | yes | Sandbox ID |
Returns: Promise<void>
pause(sandboxId)
Pause a running sandbox, creating a checkpoint of its current state. The sandbox can be resumed later with resume().
| Param | Type | Required | Description |
|---|---|---|---|
sandboxId | string | yes | Sandbox ID |
Returns: Promise<void>
resume(sandboxId)
Resume a paused or evacuated sandbox from its checkpoint.
| Param | Type | Required | Description |
|---|---|---|---|
sandboxId | string | yes | Sandbox ID |
Returns: Promise<void>
Running Background Jobs
Run processes that outlive a single execute() call. Jobs continue in the background and can be monitored or stopped.
createJob(options)
Start a long-running job in the sandbox.
| Param | Type | Required | Description |
|---|---|---|---|
options | CreateJobOptions | yes | Job configuration |
options.command | string[] | yes | Command and arguments to execute |
options.streams | object | no | Stream configuration for output capture |
options.streams.stdout | string | no | Stream ID for stdout output |
options.streams.stderr | string | no | Stream ID for stderr output |
Returns: Promise<Job>
interface Job {
jobId: string;
sandboxId: string;
command: string[];
status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
exitCode?: number | null;
startedAt?: string | null;
completedAt?: string | null;
error?: string | null;
stdoutStreamUrl?: string | null;
stderrStreamUrl?: string | null;
}Example
const sandbox = await ctx.sandbox.create({ runtime: 'bun:1' });
const job = await sandbox.createJob({
command: ['bun', 'run', 'server.ts'],
});
ctx.logger.info('Job started: %s (status: %s)', job.jobId, job.status);getJob(jobId)
Get current status and details of a job.
| Param | Type | Required | Description |
|---|---|---|---|
jobId | string | yes | Job identifier |
Returns: Promise<Job>
Example
const job = await sandbox.getJob(jobId);
ctx.logger.info('Job %s: %s (exit: %d)', job.jobId, job.status, job.exitCode);listJobs(limit?)
List jobs in the sandbox.
| Param | Type | Required | Description |
|---|---|---|---|
limit | number | no | Maximum number of jobs to return |
Returns: Promise<{ jobs: Job[] }>
Example
const { jobs } = await sandbox.listJobs();
for (const job of jobs) {
ctx.logger.info('%s: %s', job.jobId, job.status);
}stopJob(jobId, force?)
Stop a running job. By default sends SIGTERM for graceful shutdown. Use force for SIGKILL.
| Param | Type | Required | Description |
|---|---|---|---|
jobId | string | yes | Job identifier |
force | boolean | no | Use SIGKILL instead of SIGTERM |
Returns: Promise<Job> (updated job with new status)
Example
// Graceful stop
const stopped = await sandbox.stopJob(job.jobId);
// Force kill
const killed = await sandbox.stopJob(job.jobId, true);Snapshots
Snapshots capture the state of a sandbox for reuse. Access snapshot operations via ctx.sandbox.snapshot.
snapshot.create(sandboxId, options?)
Create a snapshot from a running sandbox.
| Param | Type | Required | Description |
|---|---|---|---|
sandboxId | string | yes | Sandbox ID to snapshot |
options | SnapshotCreateOptions | no | Snapshot metadata |
SnapshotCreateOptions fields (all optional):
| Field | Type | Description |
|---|---|---|
name | string | Display name (letters, numbers, underscores, dashes) |
description | string | Snapshot description |
tag | string | Version tag (defaults to 'latest') |
public | boolean | Make publicly accessible |
Returns: Promise<SnapshotInfo>
interface SnapshotInfo {
snapshotId: string;
name: string;
description?: string;
tag?: string;
sizeBytes: number;
fileCount: number;
createdAt: string;
public?: boolean;
}snapshot.get(snapshotId)
Get snapshot details. Returns: Promise<SnapshotInfo>
snapshot.list(params?)
List snapshots with optional filtering.
| Param | Type | Required | Description |
|---|---|---|---|
params | SnapshotListParams | no | Filter and pagination options |
SnapshotListParams fields (all optional):
| Field | Type | Description |
|---|---|---|
sandboxId | string | Filter by sandbox ID |
limit | number | Max results |
offset | number | Results to skip |
sort | string | Sort field |
direction | 'asc' | 'desc' | Sort direction (default 'desc') |
Returns: Promise<SnapshotListResponse> with snapshots array and total count.
snapshot.delete(snapshotId)
Delete a snapshot. Returns: Promise<void>
snapshot.tag(snapshotId, tag)
Update the tag on a snapshot. Pass null to remove the tag.
| Param | Type | Required | Description |
|---|---|---|---|
snapshotId | string | yes | Snapshot ID |
tag | string | null | yes | New tag, or null to clear |
Returns: Promise<SnapshotInfo>
Error Handling
The sandbox API throws specific errors for common failure modes:
SandboxNotFoundError: Thrown when the sandbox returns HTTP 404. This can happen if the sandbox was destroyed or is still initializing. The error includes the sandbox ID for debugging.
try {
const result = await sandbox.execute({ command: ['echo', 'hello'] });
} catch (error) {
if (error._tag === 'SandboxNotFoundError') {
ctx.logger.warn('Sandbox not ready, may still be initializing');
}
}