Skip to main content

Installation

npm install @opencomputer/sdk
import { Sandbox } from "@opencomputer/sdk";
import { Image } from "@opencomputer/sdk/dist/image.js";
import { Snapshots } from "@opencomputer/sdk/dist/snapshot.js";

Sandbox

Static Methods

Sandbox.create(opts?): Promise<Sandbox>

Create a new sandbox.
ParameterTypeDefaultDescription
templatestring"base"Template name
timeoutnumber300Idle timeout in seconds
apiKeystringenv varAPI key
apiUrlstringenv varAPI URL
envsRecord<string, string>Environment variables
metadataRecord<string, string>Arbitrary metadata
cpuCountnumberCPU cores (max 4)
memoryMBnumberMemory in MB (max 2048)
imageImageDeclarative image definition (see Image)
snapshotstringName of a pre-built snapshot
onBuildLog(log: string) => voidBuild log callback (when using image)
const sandbox = await Sandbox.create({ template: "my-stack", timeout: 600 });

Sandbox.connect(sandboxId, opts?): Promise<Sandbox>

Connect to an existing sandbox.
ParameterTypeDescription
sandboxIdstringSandbox ID
apiKeystringAPI key (optional)
apiUrlstringAPI URL (optional)
const sandbox = await Sandbox.connect("sb-abc123");

Sandbox.createFromCheckpoint(checkpointId, opts?): Promise<Sandbox>

Create a new sandbox from a checkpoint.
ParameterTypeDefaultDescription
checkpointIdstringCheckpoint ID (required)
timeoutnumber300Idle timeout
apiKeystringenv varAPI key
apiUrlstringenv varAPI URL
const forked = await Sandbox.createFromCheckpoint("cp-abc123");

Sandbox.createCheckpointPatch(checkpointId, opts): Promise<PatchResult>

Create a patch for a checkpoint.
ParameterTypeRequiredDescription
checkpointIdstringYesTarget checkpoint
scriptstringYesBash script
descriptionstringNoDescription
apiKeystringNoAPI key
apiUrlstringNoAPI URL
const result = await Sandbox.createCheckpointPatch("cp-abc", { script: "apt install -y curl" });

Sandbox.listCheckpointPatches(checkpointId, opts?): Promise<PatchInfo[]>

const patches = await Sandbox.listCheckpointPatches("cp-abc");

Sandbox.deleteCheckpointPatch(checkpointId, patchId, opts?): Promise<void>

await Sandbox.deleteCheckpointPatch("cp-abc", "pa-xyz");

Instance Methods

sandbox.kill(): Promise<void>

Terminate the sandbox.

sandbox.isRunning(): Promise<boolean>

Check if the sandbox is running.

sandbox.hibernate(): Promise<void>

Snapshot VM state and stop. No compute cost while hibernated.

sandbox.wake(opts?): Promise<void>

Resume a hibernated sandbox.
ParameterTypeDefaultDescription
timeoutnumber300Idle timeout after wake

sandbox.setTimeout(timeout): Promise<void>

Update the idle timeout.
ParameterTypeDescription
timeoutnumberNew timeout in seconds

sandbox.createCheckpoint(name): Promise<CheckpointInfo>

Create a named checkpoint.

sandbox.listCheckpoints(): Promise<CheckpointInfo[]>

List all checkpoints for the sandbox.

sandbox.restoreCheckpoint(checkpointId): Promise<void>

Revert in-place to a checkpoint.

sandbox.deleteCheckpoint(checkpointId): Promise<void>

Delete a checkpoint.

sandbox.createPreviewURL(opts): Promise<PreviewURLResult>

ParameterTypeRequiredDescription
portnumberYesContainer port (1–65535)
domainstringNoCustom domain
authConfigRecord<string, unknown>NoAuth configuration

sandbox.listPreviewURLs(): Promise<PreviewURLResult[]>

sandbox.deletePreviewURL(port): Promise<void>

Properties

PropertyTypeDescription
sandboxIdstringSandbox ID (readonly)
statusstringCurrent status (readonly)
agentAgentAgent sessions
execExecCommand execution
filesFilesystemFile operations
ptyPtyTerminal sessions
commandsExecDeprecated — alias for exec

Types

SandboxOpts

interface SandboxOpts {
  template?: string;
  timeout?: number;
  apiKey?: string;
  apiUrl?: string;
  envs?: Record<string, string>;
  metadata?: Record<string, string>;
  cpuCount?: number;
  memoryMB?: number;
  image?: Image;
  snapshot?: string;
  onBuildLog?: (log: string) => void;
}

CheckpointInfo

interface CheckpointInfo {
  id: string;
  sandboxId: string;
  orgId: string;
  name: string;
  sandboxConfig: object;
  status: string;       // "processing" | "ready" | "failed"
  sizeBytes: number;
  createdAt: string;
}

PatchInfo

interface PatchInfo {
  id: string;
  checkpointId: string;
  sequence: number;
  script: string;
  description: string;
  strategy: string;     // "on_wake"
  createdAt: string;
}

PatchResult

interface PatchResult {
  patch: PatchInfo;
}

PreviewURLResult

interface PreviewURLResult {
  id: string;
  sandboxId: string;
  orgId: string;
  hostname: string;
  customHostname?: string;
  port: number;
  cfHostnameId?: string;
  sslStatus: string;
  authConfig?: object;
  createdAt: string;
}

Agent

Accessed via sandbox.agent.

sandbox.agent.start(opts?): Promise<AgentSession>

Start an agent session.
ParameterTypeDescription
promptstringInitial prompt
modelstringClaude model
systemPromptstringSystem prompt
allowedToolsstring[]Restrict tools
permissionModestringPermission mode
maxTurnsnumberMax turns (default: 50)
cwdstringWorking directory
mcpServersRecord<string, McpServerConfig>MCP servers
resumestringResume session ID
onEvent(event: AgentEvent) => voidEvent callback
onError(data: string) => voidStderr callback
onExit(exitCode: number) => voidExit callback
onScrollbackEnd() => voidScrollback done callback
const session = await sandbox.agent.start({
  prompt: "Build a todo app",
  onEvent: (e) => console.log(e.type),
});

sandbox.agent.attach(sessionId, opts?): Promise<AgentSession>

Reconnect to a running agent session. Accepts onEvent, onError, onExit, onScrollbackEnd.

sandbox.agent.list(): Promise<AgentSessionInfo[]>

List all agent sessions.

AgentSession

MemberTypeDescription
sessionIdstringSession ID
donePromise<number>Resolves with exit code
sendPrompt(text)methodSend follow-up prompt
interrupt()methodInterrupt current turn
configure(config)methodUpdate agent configuration
kill(signal?)Promise<void>Kill agent process
close()methodClose WebSocket

Types

AgentEvent

interface AgentEvent {
  type: string;
  [key: string]: unknown;
}

McpServerConfig

interface McpServerConfig {
  command: string;
  args?: string[];
  env?: Record<string, string>;
}

Exec

Accessed via sandbox.exec.

sandbox.exec.run(command, opts?): Promise<ProcessResult>

Run a command synchronously.
ParameterTypeDefaultDescription
commandstringShell command (required)
timeoutnumber60Timeout in seconds
envRecord<string, string>Environment variables
cwdstringWorking directory
const result = await sandbox.exec.run("npm test", { cwd: "/app" });

sandbox.exec.start(command, opts?): Promise<ExecSession>

Start a long-running command with streaming.
ParameterTypeDescription
commandstringCommand (required)
argsstring[]Arguments
envRecord<string, string>Environment variables
cwdstringWorking directory
timeoutnumberTimeout in seconds
maxRunAfterDisconnectnumberSeconds to keep running after disconnect
onStdout(data: Uint8Array) => voidStdout callback
onStderr(data: Uint8Array) => voidStderr callback
onExit(exitCode: number) => voidExit callback
const session = await sandbox.exec.start("node server.js", {
  onStdout: (data) => process.stdout.write(data),
});

sandbox.exec.attach(sessionId, opts?): Promise<ExecSession>

Reconnect to a running exec session.
ParameterTypeDescription
sessionIdstringSession ID (required)
onStdout(data: Uint8Array) => voidStdout callback
onStderr(data: Uint8Array) => voidStderr callback
onExit(exitCode: number) => voidExit callback
onScrollbackEnd() => voidScrollback replay done

sandbox.exec.list(): Promise<ExecSessionInfo[]>

List all exec sessions.

sandbox.exec.kill(sessionId, signal?): Promise<void>

Kill an exec session. Default signal: 9 (SIGKILL).

ExecSession

MemberTypeDescription
sessionIdstringSession ID
donePromise<number>Resolves with exit code
sendStdin(data)methodSend input (string or Uint8Array)
kill(signal?)Promise<void>Kill process
close()methodClose WebSocket

Types

ProcessResult

interface ProcessResult {
  exitCode: number;
  stdout: string;
  stderr: string;
}

ExecSessionInfo

interface ExecSessionInfo {
  sessionID: string;
  sandboxID: string;
  command: string;
  args: string[];
  running: boolean;
  exitCode?: number;
  startedAt: string;
  attachedClients: number;
}

Filesystem

Accessed via sandbox.files.

sandbox.files.read(path): Promise<string>

Read a file as a UTF-8 string.

sandbox.files.readBytes(path): Promise<Uint8Array>

Read a file as raw bytes.

sandbox.files.write(path, content): Promise<void>

Write content to a file. Accepts string or Uint8Array.

sandbox.files.list(path?): Promise<EntryInfo[]>

List directory contents. Default path: "/".

sandbox.files.makeDir(path): Promise<void>

Create a directory (recursive).

sandbox.files.remove(path): Promise<void>

Delete a file or directory.

sandbox.files.exists(path): Promise<boolean>

Check if a path exists. Client-side wrapper — attempts a read and returns false on error.

Types

EntryInfo

interface EntryInfo {
  name: string;
  isDir: boolean;
  path: string;
  size: number;
}

Pty

Accessed via sandbox.pty.

sandbox.pty.create(opts?): Promise<PtySession>

Create an interactive terminal session.
ParameterTypeDefaultDescription
colsnumber80Terminal columns
rowsnumber24Terminal rows
onOutput(data: Uint8Array) => voidOutput callback

PtySession

MemberTypeDescription
sessionIdstringSession ID
send(data)methodSend input (string or Uint8Array)
close()methodClose the PTY

Image

Fluent, immutable builder for declarative sandbox images. Each method returns a new Image instance.

Image.base(): Image

Start from the default OpenSandbox environment (Ubuntu 22.04, Python, Node.js, build tools).
import { Image } from "@opencomputer/sdk";

const image = Image.base()
  .aptInstall(['curl', 'jq'])
  .pipInstall(['requests', 'pandas'])
  .env({ PROJECT_ROOT: '/workspace' })
  .workdir('/workspace');

Builder Methods

MethodParametersDescription
aptInstall(packages)string[]Install system packages via apt-get
pipInstall(packages)string[]Install Python packages via pip
runCommands(...cmds)string[]Run shell commands during build
env(vars)Record<string, string>Set environment variables
workdir(path)stringSet default working directory
addFile(remotePath, content)string, stringEmbed a file with inline content
addLocalFile(localPath, remotePath)string, stringRead a local file into the image
addLocalDir(localPath, remotePath)string, stringRead a local directory into the image

image.toJSON(): ImageManifest

Returns the image manifest as a plain object.

image.cacheKey(): string

Computes a deterministic SHA-256 hash of the manifest for cache lookups.

Snapshots

Standalone class — not a property on Sandbox.

new Snapshots(opts?)

import { Snapshots } from "@opencomputer/sdk";

const snapshots = new Snapshots();
// or with explicit config:
const snapshots = new Snapshots({ apiKey: "...", apiUrl: "..." });
ParameterTypeDescription
apiKeystringAPI key (falls back to OPENCOMPUTER_API_KEY env var)
apiUrlstringAPI URL (falls back to OPENCOMPUTER_API_URL env var)

snapshots.create(opts): Promise<SnapshotInfo>

Create a pre-built snapshot from a declarative image.
ParameterTypeRequiredDescription
namestringYesUnique snapshot name
imageImageYesDeclarative image definition
onBuildLogs(log: string) => voidNoBuild log streaming callback

snapshots.list(): Promise<SnapshotInfo[]>

List all snapshots for the current organization.

snapshots.get(name): Promise<SnapshotInfo>

Get a snapshot by name.

snapshots.delete(name): Promise<void>

Delete a snapshot. Existing sandboxes created from it are not affected.

Types

SnapshotInfo

interface SnapshotInfo {
  id: string;
  name: string;
  status: string;       // "building" | "ready" | "failed"
  contentHash: string;
  checkpointId: string;
  manifest: object;
  createdAt: string;
  lastUsedAt: string;
}

Secret Stores

SecretStore.create(opts)

Create a new secret store.
import { SecretStore } from '@opencomputer/sdk';

const store = await SecretStore.create({
  name: 'my-agent-secrets',
  egressAllowlist: ['api.anthropic.com'],
});
opts
CreateSecretStoreOpts
required
Returns: Promise<SecretStoreInfo>

SecretStore.list(opts?)

List all secret stores.
const stores = await SecretStore.list();
Returns: Promise<SecretStoreInfo[]>

SecretStore.get(storeId, opts?)

Get a secret store by ID.
const store = await SecretStore.get('store-uuid');
storeId
string
required
UUID of the secret store.
Returns: Promise<SecretStoreInfo>

SecretStore.update(storeId, opts)

Partial updates — only the fields you pass are changed.
const updated = await SecretStore.update('store-uuid', {
  name: 'new-name',
  egressAllowlist: ['api.anthropic.com', '*.openai.com'],
});
storeId
string
required
UUID of the store to update.
opts
UpdateSecretStoreOpts
required
Returns: Promise<SecretStoreInfo>

SecretStore.delete(storeId, opts?)

Deletes the store and all its secrets. Running sandboxes are not affected.
await SecretStore.delete('store-uuid');
Returns: Promise<void>

SecretStore.setSecret(storeId, name, value, opts?)

Set a secret in a store. Secrets are encrypted at rest. The value is never returned by the API.
await SecretStore.setSecret('store-uuid', 'ANTHROPIC_API_KEY', 'sk-ant-...');
Optionally restrict which hosts can receive this secret:
await SecretStore.setSecret('store-uuid', 'ANTHROPIC_API_KEY', 'sk-ant-...', {
  allowedHosts: ['api.anthropic.com'],
});
storeId
string
required
UUID of the secret store.
name
string
required
Secret name (used as the env var name in sandboxes).
value
string
required
Secret value (encrypted at rest, never returned by API).
Returns: Promise<void>

SecretStore.listSecrets(storeId, opts?)

Returns secret metadata only. Values are never exposed.
const entries = await SecretStore.listSecrets('store-uuid');
// [{ name: 'ANTHROPIC_API_KEY', allowedHosts: ['api.anthropic.com'], ... }, ...]
Returns: Promise<SecretEntryInfo[]>

SecretStore.deleteSecret(storeId, name, opts?)

await SecretStore.deleteSecret('store-uuid', 'DATABASE_URL');
Returns: Promise<void>

Creating a Sandbox with a Secret Store

Pass the secretStore option to Sandbox.create() to inject the store’s secrets:
import { Sandbox } from '@opencomputer/sdk';

const sandbox = await Sandbox.create({
  secretStore: 'my-agent-secrets',
  timeout: 600,
});

// Secrets are available as sealed env vars
const result = await sandbox.commands.run('echo $ANTHROPIC_API_KEY');
// stdout: "osb_sealed_abc123..." (sealed, not the real key)

// But outbound HTTPS requests get the real value substituted by the proxy
const apiResult = await sandbox.commands.run(
  'curl -s https://api.anthropic.com/v1/messages -H "x-api-key: $ANTHROPIC_API_KEY" ...'
);
// The proxy replaces the sealed token with the real key before it hits Anthropic

Types

SecretStoreInfo

PropertyTypeDescription
idstringStore UUID
orgIdstringOrganization UUID
namestringStore name
egressAllowliststring[]Allowed egress hosts
createdAtstringISO 8601 timestamp
updatedAtstringISO 8601 timestamp

SecretEntryInfo

PropertyTypeDescription
idstringEntry UUID
storeIdstringParent store UUID
namestringSecret name (env var name)
allowedHostsstring[]Host restrictions for this secret
createdAtstringISO 8601 timestamp
updatedAtstringISO 8601 timestamp