Services/Sandbox

Using the Sandbox API

Programmatic API for creating and managing sandboxes

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}') },
]);

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:

How Snapshots Work

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:

VariableDescription
AGENTUITY_SANDBOX_IDThe sandbox's unique identifier
AGENTUITY_SANDBOX_RUNTIMERuntime name (e.g., python, bun)
AGENTUITY_SANDBOX_RUNTIME_IDRuntime unique identifier
AGENTUITY_SANDBOX_ORG_IDOrganization ID
AGENTUITY_SANDBOX_PROJECT_IDProject ID (only when project context exists)
AGENTUITY_SANDBOX_URLPublic 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

OptionTypeDescription
runtimestringRuntime environment: 'bun:1', 'python:3.14'
namestringOptional sandbox name
descriptionstringOptional description
resources.memorystringMemory limit: '256Mi', '1Gi'
resources.cpustringCPU in millicores: '500m', '1000m'
resources.diskstringDisk limit: '512Mi', '2Gi'
network.enabledbooleanEnable outbound network (default: false)
timeout.idlestringAuto-destroy after idle: '10m', '1h'
timeout.executionstringMax command duration: '30s', '5m'
dependenciesstring[]Apt packages: ['python3', 'git']
snapshotstringSnapshot ID or tag to restore from
envRecord<string, string>Environment variables
metadataRecord<string, unknown>User-defined metadata for tracking

ExecuteOptions

OptionTypeDescription
commandstring[]Command and arguments
filesFileToWrite[]Files to create before execution
timeoutstringOverride execution timeout
signalAbortSignalCancel the execution

Execution

Returned by sandbox.execute():

FieldTypeDescription
executionIdstringUnique execution ID for debugging
statusstring'queued', 'running', 'completed', 'failed', 'timeout', 'cancelled'
exitCodenumberProcess exit code (when completed)
durationMsnumberExecution duration in milliseconds
stdoutStreamUrlstringURL to fetch stdout stream
stderrStreamUrlstringURL to fetch stderr stream

SandboxRunResult

FieldTypeDescription
sandboxIdstringSandbox ID (for debugging)
exitCodenumberProcess exit code
durationMsnumberExecution duration
stdoutstringCaptured stdout (if available)
stderrstringCaptured stderr (if available)

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

Next Steps

  • Snapshots: Skip dependency installation with pre-configured environments
  • CLI Commands: Debug sandboxes and create snapshots from the terminal

Need Help?

Join our DiscordCommunity for assistance or just to hang with other humans building agents.

Send us an email at hi@agentuity.com if you'd like to get in touch.

Please Follow us on

If you haven't already, please Signup for your free account now and start building your first agent!