Skip to main content

Overview

The SDK provides SandboxManager (accessed via rt.sandbox) for creating and managing sandboxes, and Sandbox instances with real-time status/metrics subscriptions via Convex.
The SDK is not yet published to npm. Install from GitHub: npm install github:runtools-ai/runtools-sdk

Creating Sandboxes

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

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

// Create with default template (base-ubuntu)
const sandbox = await rt.sandbox.create();

// Create with options
const sandbox = await rt.sandbox.create({
  template: 'desktop-ubuntu',
  name: 'my-dev-env',
  sshKeys: ['ssh-ed25519 AAAA... user@laptop'],
  idleTimeoutSeconds: 1800,
  vcpus: 4,
  memoryMb: 4096,
  tags: { project: 'my-app' },
  env: { NODE_ENV: 'development' },
});

SandboxCreateOptions

FieldTypeDefaultDescription
templatestring'base-ubuntu'Template: base-ubuntu or desktop-ubuntu
namestring-Friendly name
sshKeysstring[]-SSH public keys to inject
passwordstring-Root password (alternative to SSH keys)
idleTimeoutSecondsnumber600Auto-pause after inactivity (0 = disabled)
vcpusnumber2vCPU count
memoryMbnumber1024Memory in MB
tagsRecord-Key-value tags
envRecord-Environment variables
waitForReadybooleanfalseWait for SSH/VNC readiness before returning

Listing Sandboxes

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

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

// Each item: { id, name?, status, template?, tags?, createdAt }

Destroying Sandboxes

// Destroy by ID (manager method)
await rt.sandbox.destroy('sandbox-abc123');

Sandbox Instance Methods

After creating a sandbox, you get a Sandbox instance:
const sandbox = await rt.sandbox.create({ template: 'base-ubuntu' });

Wait for Ready

// Wait until SSH (and VNC for desktop) is ready
await sandbox.waitForReady();       // Default 60s timeout
await sandbox.waitForReady(120000); // Custom timeout (ms)

Execute Commands

const result = await sandbox.exec('ls -la');
console.log(result.stdout);    // Directory listing
console.log(result.stderr);    // Error output
console.log(result.exitCode);  // 0 = success

// With options
const result = await sandbox.exec('npm install', {
  timeout: 120000,  // 2 minutes
  cwd: '/workspace',
  env: { CI: 'true' },
});

Pause and Resume

await sandbox.pause();   // Snapshot VM state to disk
await sandbox.resume();  // Restore from snapshot (~500ms)

Destroy

await sandbox.destroy(); // Closes subscriptions + deletes sandbox

Close Subscriptions

await sandbox.close(); // Closes Convex subscriptions only (sandbox keeps running)

Real-Time Events (Convex)

The SDK uses Convex WebSocket subscriptions for real-time status and metrics. Events auto-start when you register the first listener.
// Status changes (running, paused, stopped, etc.)
sandbox.on('status', (state: SandboxState) => {
  console.log('Status:', state.status);
  console.log('SSH Ready:', state.sshReady);
  console.log('VNC Ready:', state.vncReady);
  console.log('Template:', state.template);
});

// Live metrics (~1 update/second)
sandbox.on('metrics', (m: SandboxMetrics) => {
  console.log('CPU:', m.cpuPercent, '%');
  console.log('Memory:', m.memUsedPercent, '%');
  console.log('Net RX:', m.netRxBytesPerSec, 'bytes/s');
  console.log('Disk Read:', m.diskReadBytesPerSec, 'bytes/s');
});

// Fires once when SSH becomes ready
sandbox.on('ready', () => {
  console.log('Sandbox is ready!');
});

// Error events
sandbox.on('error', (err) => {
  console.error('Error:', err);
});

// Subscription closed
sandbox.on('close', () => {
  console.log('Subscriptions closed');
});

Current State Accessors

sandbox.id;        // Sandbox ID
sandbox.status;    // Current status string
sandbox.sshReady;  // boolean
sandbox.vncReady;  // boolean
sandbox.state;     // Full SandboxState object (or null)
sandbox.metrics;   // Full SandboxMetrics object (or null)

Types

import type {
  Sandbox,
  SandboxManager,
  SandboxState,
  SandboxMetrics,
  SandboxCreateOptions,
  SandboxEventType,
  SandboxEvents,
} from '@runtools/sdk';

SandboxState

FieldTypeDescription
sandboxIdstringSandbox ID
statusstringcreating, running, paused, stopped
templatestringTemplate name
sshReadybooleanSSH is accessible
vncReadybooleanVNC is accessible (desktop only)
ipstringVM internal IP
publicIpstringFC Agent public IP
sshPortnumberSSH forwarded port
vncPortnumberVNC forwarded port
vncUrlstringFull VNC URL

SandboxMetrics

FieldTypeDescription
cpuPercentnumberCPU usage %
memTotalBytesnumberTotal memory
memUsedBytesnumberUsed memory
memUsedPercentnumberMemory usage %
netRxBytesPerSecnumberNetwork receive rate
netTxBytesPerSecnumberNetwork transmit rate
diskReadBytesPerSecnumberDisk read rate
diskWriteBytesPerSecnumberDisk write rate

What’s NOT Available in the SDK

The following are not in the SDK (use REST API or CLI instead):
  • sandbox.files.* — Use sandbox.exec('cat file.txt') instead
  • sandbox.getUrl() — URL pattern is https://{port}-{sandboxId}.sandboxes.runtools.ai
  • sandbox.getSSH() — SSH via ssh {sandboxId}@ssh.runtools.ai
  • sandbox.snapshot() / sandbox.rollback() — Use CLI: runtools sandbox snapshot/rollback
  • sandbox.branch() — Not implemented
  • sandbox.execStream() — Not implemented
  • rt.agents.* — Not implemented in SDK
  • rt.tools.* — Not implemented in SDK