Skip to main content

Creating Sandboxes

import { RunTools } from '@runtools/sdk';

const rt = new RunTools({ apiKey: process.env.RUNTOOLS_API_KEY });

// Basic creation (ephemeral, no mounts)
const sandbox = await rt.sandboxes.create({
  template: 'nodejs-20',
});

// With persistent mount
const sandbox = await rt.sandboxes.create({
  template: 'nodejs-20',
  mounts: [
    { workspaceId: 'my-project', path: '/workspace' },
  ],
});

// Multiple mounts
const sandbox = await rt.sandboxes.create({
  template: 'nodejs-20',
  mounts: [
    { workspaceId: 'my-code', path: '/workspace' },
    { workspaceId: 'datasets', path: '/data' },
  ],
});

// With all options
const sandbox = await rt.sandboxes.create({
  template: 'python-ml',
  idleTimeout: 600,
  mounts: [
    { workspaceId: 'ml-experiments', path: '/workspace' },
    { workspaceId: 'training-data', path: '/data' },
  ],
  resources: {
    vcpus: 4,
    memory: '8GB',
    disk: '50GB',
  },
  env: {
    NODE_ENV: 'development',
  },
  metadata: {
    projectId: 'proj-123',
    userId: 'user-456',
  },
});

Getting Sandboxes

// Get by ID
const sandbox = await rt.sandboxes.get('sandbox-abc123');

// List all
const sandboxes = await rt.sandboxes.list();

// Filter
const running = await rt.sandboxes.list({ 
  status: 'running' 
});

const userSandboxes = await rt.sandboxes.list({ 
  metadata: { userId: 'user-456' } 
});

Executing Commands

// Simple execution
const result = await sandbox.exec('ls -la');
console.log(result.stdout);
console.log(result.stderr);
console.log(result.exitCode);

// With options
const result = await sandbox.exec('npm run build', {
  timeout: 120000,  // 2 minutes
  cwd: '/app',      // Working directory
  env: { CI: 'true' },
});

// Stream output
for await (const chunk of sandbox.execStream('npm run dev')) {
  process.stdout.write(chunk);
}

// Background process
await sandbox.exec('node server.js &');

File Operations

// Write file
await sandbox.files.write('/app/index.js', `
console.log('Hello World');
`);

// Read file
const content = await sandbox.files.read('/app/index.js');

// List directory
const files = await sandbox.files.list('/app');
// → [{ name: 'index.js', type: 'file', size: 28 }]

// Check if exists
const exists = await sandbox.files.exists('/app/index.js');

// Delete file
await sandbox.files.remove('/app/old.js');

// Create directory
await sandbox.files.mkdir('/app/src');

// Surgical edit
await sandbox.files.replace('/app/index.js', {
  old: 'Hello World',
  new: 'Hello RunTools',
});

// Upload file
await sandbox.files.upload('/app/data.json', localBuffer);

// Download file
const buffer = await sandbox.files.download('/app/data.json');

Dev Server URLs

// Get URL for port
const url = await sandbox.getUrl({ port: 3000 });
console.log(url); // https://sandbox-abc123.sandboxes.runtools.ai

// With custom subdomain
const url = await sandbox.getUrl({ 
  port: 3000,
  subdomain: 'my-app',
});
// → https://my-app.sandboxes.runtools.ai

// List all URLs
const urls = await sandbox.getUrls();

Pause and Resume

// Pause (snapshot state)
await sandbox.pause();

// Resume (restore state)
await sandbox.resume();

// Check status
console.log(sandbox.status); // 'running' | 'paused' | 'stopped'

Snapshots

// Create snapshot
await sandbox.snapshot({ name: 'before-changes' });

// List snapshots
const snapshots = await sandbox.snapshots.list();

// Rollback
await sandbox.rollback({ snapshot: 'before-changes' });

// Branch (create new sandbox from snapshot)
const branched = await sandbox.branch({
  snapshot: 'before-changes',
  name: 'experiment',
});

SSH Access

SSH access uses your organization’s registered SSH keys:
// Get SSH connection info
const ssh = await sandbox.getSSH();
console.log(ssh.host);     // ssh.runtools.ai
console.log(ssh.username); // sandbox-abc123 (sandbox ID)
console.log(ssh.port);     // 22

// Connect via: ssh [email protected]
You must register your SSH public key first using runtools ssh-key add or via the dashboard. The SSH gateway matches your local private key against your org’s registered keys.

VNC Access (Desktop Templates)

VNC access is available for desktop-enabled templates. Coming soon.

Lifecycle

// Destroy sandbox
await sandbox.destroy();

// Wait for status
await sandbox.waitFor('running');

// Refresh status
await sandbox.refresh();

Events

// Listen for events
sandbox.on('status', (status) => {
  console.log('Status changed:', status);
});

sandbox.on('log', (log) => {
  console.log(log.message);
});

// Remove listener
sandbox.off('status', handler);

Types

import type {
  Sandbox,
  SandboxStatus,
  SandboxCreateOptions,
  ExecResult,
  FileInfo,
} from '@runtools/sdk';

const status: SandboxStatus = 'running';