Access sandbox functionality through ctx.sandbox in agents or c.var.sandbox in routes. Choose between one-shot execution for single commands or interactive sandboxes for multi-step workflows.
One-shot Execution
Use sandbox.run() when you need to execute a single command. The sandbox is automatically created and destroyed.
import { createAgent } from '@agentuity/runtime';
import { z } from 'zod';
const agent = createAgent('CodeRunner', {
schema: {
input: z.object({ code: z.string() }),
output: z.object({
success: z.boolean(),
output: z.string(),
exitCode: z.number(),
}),
},
handler: async (ctx, input) => {
const result = await ctx.sandbox.run({
command: {
exec: ['python3', '-c', input.code],
},
resources: { memory: '256Mi', cpu: '500m' },
timeout: { execution: '30s' },
});
return {
success: result.exitCode === 0,
output: result.stdout || result.stderr || '',
exitCode: result.exitCode,
};
},
});With File Input
Write files to the sandbox before execution:
const result = await ctx.sandbox.run({
command: {
exec: ['bun', 'run', 'index.ts'],
files: [
{
path: 'index.ts',
content: Buffer.from('console.log("Hello from TypeScript!")'),
},
{
path: 'data.json',
content: Buffer.from(JSON.stringify({ items: [1, 2, 3] })),
},
],
},
resources: { memory: '512Mi' },
});Interactive Sandbox
Use sandbox.create() for multi-step workflows. The sandbox persists until you explicitly destroy it.
import { createAgent } from '@agentuity/runtime';
const agent = createAgent('ProjectBuilder', {
handler: async (ctx, input) => {
// Create a persistent sandbox
const sandbox = await ctx.sandbox.create({
resources: { memory: '1Gi', cpu: '1000m' },
network: { enabled: true }, // Allow package downloads
dependencies: ['git'], // Pre-install apt packages
});
try {
// Run multiple commands in sequence
await sandbox.execute({ command: ['npm', 'init', '-y'] });
await sandbox.execute({ command: ['npm', 'install', 'zod'] });
// Write project files
await sandbox.writeFiles([
{
path: 'index.ts',
content: Buffer.from(`
import { z } from 'zod';
const schema = z.object({ name: z.string() });
console.log(schema.parse({ name: 'test' }));
`),
},
]);
// Build and run
const result = await sandbox.execute({
command: ['npx', 'tsx', 'index.ts'],
});
return { output: result.stdoutStreamUrl };
} finally {
// Always clean up
await sandbox.destroy();
}
},
});Writing Files
Write files to the sandbox workspace before or during execution:
await sandbox.writeFiles([
{ path: 'src/main.py', content: Buffer.from('print("Hello")') },
{ path: 'config.json', content: Buffer.from('{"debug": true}') },
]);Exposing Ports
Expose a port from the sandbox to make it accessible via a public URL:
const sandbox = await ctx.sandbox.create({
network: {
enabled: true,
port: 3000, // Expose port 3000 (valid range: 1024-65535)
},
resources: { memory: '512Mi' },
});
// Start a web server inside the sandbox
await sandbox.execute({ command: ['npm', 'run', 'serve'] });
// Get the public URL
const info = await ctx.sandbox.get(sandbox.id);
if (info.url) {
ctx.logger.info('Server accessible at', { url: info.url, port: info.networkPort });
}Setting network.port requires network.enabled: true. The sandbox must have network access to expose ports.
Project Association
Associate sandboxes with a project for organization and filtering:
const sandbox = await ctx.sandbox.create({
projectId: 'proj_abc123', // Associate with project
resources: { memory: '512Mi' },
});
// List sandboxes by project
const { sandboxes } = await ctx.sandbox.list({
projectId: 'proj_abc123',
});Reading Files
Read files from the sandbox as streams:
const stream = await sandbox.readFile('output/results.json');
const reader = stream.getReader();
const chunks: Uint8Array[] = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
const content = new TextDecoder().decode(Buffer.concat(chunks));
const data = JSON.parse(content);Streaming Output
Access stdout and stderr as streams for real-time output:
const sandbox = await ctx.sandbox.create();
// Start a long-running command
await sandbox.execute({ command: ['npm', 'run', 'build'] });
// Stream stdout with error handling
try {
const reader = sandbox.stdout.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
ctx.logger.info('Build output', { line: decoder.decode(value) });
}
} catch (error) {
ctx.logger.error('Failed to read stream', { error });
}Creating from Snapshot
Start sandboxes from pre-configured snapshots for faster cold starts:
A snapshot is a saved filesystem state. You create sandboxes from snapshots rather than running them directly. See Snapshots for how to create them.
const sandbox = await ctx.sandbox.create({
snapshot: 'node-project-base', // Use tag or snapshot ID
resources: { memory: '512Mi' },
});
// Sandbox already has node_modules and dependencies installed
await sandbox.execute({ command: ['npm', 'run', 'build'] });Environment Variables
Pass environment variables to sandboxes:
const result = await ctx.sandbox.run({
command: { exec: ['node', '-e', 'console.log(process.env.API_KEY)'] },
env: {
API_KEY: 'secret-key',
NODE_ENV: 'test',
DEBUG: 'true',
},
resources: { memory: '256Mi' },
});Automatic Environment Variables
Every sandbox automatically receives environment variables that provide context about its runtime environment, letting your code access the sandbox ID, public URL, and more:
| Variable | Description |
|---|---|
AGENTUITY_SANDBOX_ID | The sandbox's unique identifier |
AGENTUITY_SANDBOX_RUNTIME | Runtime name (e.g., python, bun) |
AGENTUITY_SANDBOX_RUNTIME_ID | Runtime unique identifier |
AGENTUITY_SANDBOX_ORG_ID | Organization ID |
AGENTUITY_SANDBOX_PROJECT_ID | Project ID (only when project context exists) |
AGENTUITY_SANDBOX_URL | Public URL (only when network is enabled) |
const result = await ctx.sandbox.run({
command: {
exec: ['node', '-e', `
console.log('Sandbox:', process.env.AGENTUITY_SANDBOX_ID);
console.log('Runtime:', process.env.AGENTUITY_SANDBOX_RUNTIME);
if (process.env.AGENTUITY_SANDBOX_URL) {
console.log('URL:', process.env.AGENTUITY_SANDBOX_URL);
}
`],
},
network: { enabled: true },
resources: { memory: '256Mi' },
});Note that the code snippet above runs inside an isolated sandbox, not in the agent, so use standard logging (console.log, print, etc.) rather than ctx.logger.
Cancelling Execution
Use an AbortSignal to cancel long-running commands:
const controller = new AbortController();
// Set a 5-second timeout
setTimeout(() => controller.abort(), 5000);
try {
const result = await sandbox.execute({
command: ['npm', 'run', 'long-task'],
signal: controller.signal,
});
return { output: result.stdout };
} catch (error) {
if (error.name === 'AbortError') {
ctx.logger.warn('Execution cancelled');
return { output: '', cancelled: true };
}
throw error;
}Using in Routes
Routes access sandbox through c.var.sandbox:
import { createRouter } from '@agentuity/runtime';
const router = createRouter();
router.post('/execute', async (c) => {
const { language, code } = await c.req.json();
const commands: Record<string, string[]> = {
python: ['python3', '-c', code],
javascript: ['node', '-e', code],
typescript: ['bun', '-e', code],
};
if (!commands[language]) {
return c.json({ error: 'Unsupported language' }, 400);
}
const result = await c.var.sandbox.run({
command: { exec: commands[language] },
timeout: { execution: '10s' },
resources: { memory: '128Mi', cpu: '250m' },
});
return c.json({
success: result.exitCode === 0,
output: result.stdout || result.stderr,
exitCode: result.exitCode,
durationMs: result.durationMs,
});
});
export default router;Sandbox Management
Listing Sandboxes
const { sandboxes, total } = await ctx.sandbox.list({
status: 'idle', // Filter by status
projectId: 'proj_x', // Filter by project
snapshotId: 'snp_y', // Filter by snapshot
limit: 10,
offset: 0,
});
for (const info of sandboxes) {
ctx.logger.info('Sandbox', {
id: info.sandboxId,
status: info.status,
executions: info.executions,
});
}Getting Sandbox Info
const info = await ctx.sandbox.get('sbx_abc123');
ctx.logger.info('Sandbox details', {
status: info.status,
createdAt: info.createdAt,
snapshotId: info.snapshotId,
});Destroying Sandboxes
// Via sandbox instance
await sandbox.destroy();
// Via service (by ID)
await ctx.sandbox.destroy('sbx_abc123');Configuration Reference
SandboxCreateOptions
| Option | Type | Description |
|---|---|---|
runtime | string | Runtime environment: 'bun:1', 'python:3.14' |
name | string | Optional sandbox name |
description | string | Optional description |
resources.memory | string | Memory limit: '256Mi', '1Gi' |
resources.cpu | string | CPU in millicores: '500m', '1000m' |
resources.disk | string | Disk limit: '512Mi', '2Gi' |
network.enabled | boolean | Enable outbound network (default: false) |
network.port | number | Port to expose to internet (1024-65535) |
projectId | string | Associate sandbox with a project |
timeout.idle | string | Auto-destroy after idle: '10m', '1h' |
timeout.execution | string | Max command duration: '30s', '5m' |
dependencies | string[] | Apt packages: ['python3', 'git'] |
snapshot | string | Snapshot ID or tag to restore from |
env | Record<string, string> | Environment variables |
metadata | Record<string, unknown> | User-defined metadata for tracking |
ExecuteOptions
| Option | Type | Description |
|---|---|---|
command | string[] | Command and arguments |
files | FileToWrite[] | Files to create before execution |
timeout | string | Override execution timeout |
signal | AbortSignal | Cancel the execution |
Execution
Returned by sandbox.execute():
| Field | Type | Description |
|---|---|---|
executionId | string | Unique execution ID for debugging |
status | string | 'queued', 'running', 'completed', 'failed', 'timeout', 'cancelled' |
exitCode | number | Process exit code (when completed) |
durationMs | number | Execution duration in milliseconds |
stdoutStreamUrl | string | URL to fetch stdout stream |
stderrStreamUrl | string | URL to fetch stderr stream |
cpuTimeMs | number | CPU time consumed in milliseconds |
memoryByteSec | number | Memory usage in byte-seconds |
networkEgressBytes | number | Outbound network traffic in bytes |
SandboxRunResult
| Field | Type | Description |
|---|---|---|
sandboxId | string | Sandbox ID (for debugging) |
exitCode | number | Process exit code |
durationMs | number | Execution duration |
stdout | string | Captured stdout (if available) |
stderr | string | Captured stderr (if available) |
cpuTimeMs | number | CPU time consumed in milliseconds |
memoryByteSec | number | Memory usage in byte-seconds |
networkEgressBytes | number | Outbound network traffic in bytes |
SandboxInfo
Returned by ctx.sandbox.get() and in list results:
| Field | Type | Description |
|---|---|---|
sandboxId | string | Unique sandbox identifier |
status | SandboxStatus | 'creating', 'idle', 'running', 'terminated', 'failed', 'deleted' |
createdAt | string | ISO timestamp |
snapshotId | string | Source snapshot (if created from snapshot) |
networkPort | number | Port exposed from sandbox (if configured) |
url | string | Public URL (when port is configured) |
user | SandboxUserInfo | User who created the sandbox |
agent | SandboxAgentInfo | Agent that created the sandbox |
project | SandboxProjectInfo | Associated project |
org | SandboxOrgInfo | Organization (always present) |
Access context information from sandbox info:
const info = await ctx.sandbox.get('sbx_abc123');
// Organization is always present
ctx.logger.info('Organization', { id: info.org.id, name: info.org.name });
// User info (when created by a user)
if (info.user) {
ctx.logger.info('Created by', {
userId: info.user.id,
name: `${info.user.firstName} ${info.user.lastName}`,
});
}
// Agent info (when created by an agent)
if (info.agent) {
ctx.logger.info('Agent', { id: info.agent.id, name: info.agent.name });
}
// Project info (when associated with a project)
if (info.project) {
ctx.logger.info('Project', { id: info.project.id, name: info.project.name });
}Snapshot Management API
Manage snapshots programmatically through ctx.sandbox.snapshot. This lets agents create, list, and manage snapshots without CLI access.
Creating Snapshots
Save the current state of a sandbox as a snapshot:
const sandbox = await ctx.sandbox.create({
network: { enabled: true },
resources: { memory: '1Gi' },
});
// Set up the environment
await sandbox.execute({ command: ['npm', 'init', '-y'] });
await sandbox.execute({ command: ['npm', 'install', 'typescript', 'zod'] });
// Save as snapshot
const snapshot = await ctx.sandbox.snapshot.create(sandbox.id, {
name: 'typescript-zod-env',
description: 'TypeScript environment with Zod validation',
tag: 'latest',
public: false, // Keep private to your org
});
ctx.logger.info('Snapshot created', {
snapshotId: snapshot.snapshotId,
sizeBytes: snapshot.sizeBytes,
fileCount: snapshot.fileCount,
});
await sandbox.destroy();Listing Snapshots
const { snapshots, total } = await ctx.sandbox.snapshot.list({
sandboxId: 'sbx_abc123', // Filter by source sandbox
limit: 50,
offset: 0,
});
for (const snap of snapshots) {
ctx.logger.info('Snapshot', {
id: snap.snapshotId,
name: snap.name,
tag: snap.tag,
createdAt: snap.createdAt,
});
}Getting Snapshot Details
const snapshot = await ctx.sandbox.snapshot.get('snp_xyz789');
ctx.logger.info('Snapshot details', {
name: snapshot.name,
sizeBytes: snapshot.sizeBytes,
fileCount: snapshot.fileCount,
files: snapshot.files, // Array of file info
});Tagging Snapshots
Update or remove a snapshot's tag:
// Add or update tag
await ctx.sandbox.snapshot.tag('snp_xyz789', 'v1.0');
// Point "latest" to a new snapshot
await ctx.sandbox.snapshot.tag('snp_newversion', 'latest');
// Remove tag
await ctx.sandbox.snapshot.tag('snp_xyz789', null);Deleting Snapshots
await ctx.sandbox.snapshot.delete('snp_xyz789');SnapshotCreateOptions
| Option | Type | Description |
|---|---|---|
name | string | Display name (URL-safe: letters, numbers, underscores, dashes) |
description | string | Description of the snapshot |
tag | string | Tag name (defaults to "latest") |
public | boolean | Make snapshot publicly accessible (default: false) |
SnapshotInfo
Returned by create, get, and list operations:
| Field | Type | Description |
|---|---|---|
snapshotId | string | Unique identifier |
name | string | Display name |
tag | string | null | Current tag |
sizeBytes | number | Total size in bytes |
fileCount | number | Number of files |
files | SnapshotFileInfo[] | File details (path, size, mime type) |
createdAt | string | ISO timestamp |
downloadUrl | string | URL to download snapshot archive |
public | boolean | Whether publicly accessible |
Best Practices
- Set resource limits: Control memory and CPU usage for predictable performance
- Use timeouts: Always set execution timeouts for untrusted code
- Enable network when needed: Required for package installation, API calls, and external requests
- Clean up interactive sandboxes: Use try/finally to ensure
destroy()is called - Use snapshots for common environments: Pre-install dependencies to reduce cold start time
- Tag important snapshots: Use semantic versioning tags (
v1.0,latest) for reproducibility
Next Steps
- Snapshots: CLI commands and declarative snapshot definitions
- CLI Commands: Debug sandboxes from the terminal