Skip to main content
Two modes: exec.run() waits for the result, exec.start() creates a session for long-running or streaming commands.
import { Sandbox } from "@opencomputer/sdk";

const sandbox = await Sandbox.create();
const result = await sandbox.exec.run("echo Hello, World!");
console.log(result.stdout); // "Hello, World!\n"
await sandbox.kill();

Quick Commands: exec.run()

Run a shell command and wait for the result. The command runs via sh -c, so pipes, redirects, and shell expansion work.
// Working directory and environment variables
const result = await sandbox.exec.run("npm run build", {
  cwd: "/app",
  env: { NODE_ENV: "production" },
  timeout: 120,
});

if (result.exitCode !== 0) {
  console.error("Build failed:", result.stderr);
}

Parameters

ParameterTypeDefaultDescription
commandstringShell command to run (required)
timeoutnumber60Timeout in seconds
envobjectEnvironment variables
cwdstringWorking directory

ProcessResult

FieldTypeScriptPythonType
Exit codeexitCodeexit_codenumber
Standard outputstdoutstdoutstring
Standard errorstderrstderrstring

Async Commands: exec.start()

Start a command as an exec session for long-running processes or streaming output. The TypeScript and Python SDKs differ significantly here.

TypeScript — Full Streaming

Returns an ExecSession with callbacks for stdout, stderr, and exit:
const session = await sandbox.exec.start("node server.js", {
  cwd: "/app",
  env: { PORT: "3000" },
  onStdout: (data) => process.stdout.write(data),
  onStderr: (data) => process.stderr.write(data),
  onExit: (code) => console.log("Server exited:", code),
  maxRunAfterDisconnect: 300, // keep running 5min after disconnect
});

// Send input
session.sendStdin("some input\n");

// Wait for completion (or kill)
await session.kill();

ExecStartOpts

ParameterTypeDescription
argsstring[]Command arguments
envobjectEnvironment variables
cwdstringWorking directory
timeoutnumberTimeout in seconds
maxRunAfterDisconnectnumberSeconds to keep running after disconnect
onStdoutcallback(data: Uint8Array) => void
onStderrcallback(data: Uint8Array) => void
onExitcallback(exitCode: number) => void

ExecSession

MemberTypeDescription
sessionIdstringSession ID
donePromise<number>Resolves with exit code
sendStdin(data)methodSend input to the process
kill(signal?)methodKill the process (default: SIGKILL)
close()methodClose the WebSocket connection

Python — Session ID

Python’s exec.start() returns a session ID string. There are no streaming callbacks or ExecSession object.
session_id = await sandbox.exec.start(
    "node server.js",
    args=None,
    env={"PORT": "3000"},
    cwd="/app",
)

# Check session status
sessions = await sandbox.exec.list()
for s in sessions:
    print(s.session_id, "running" if s.running else f"exited ({s.exit_code})")

# Kill when done
await sandbox.exec.kill(session_id)
Python does not support exec.attach(), streaming callbacks, maxRunAfterDisconnect, or the ExecSession object. For streaming in Python, use the WebSocket binary protocol directly.

Managing Sessions

List Sessions

const sessions = await sandbox.exec.list();
for (const s of sessions) {
  console.log(s.sessionID, s.running ? "running" : `exited (${s.exitCode})`);
  console.log(`  command: ${s.command}, clients: ${s.attachedClients}`);
}

Attach to Running Session (TypeScript only)

Reconnect to a running exec session to resume streaming output:
const session = await sandbox.exec.attach(sessionId, {
  onStdout: (data) => process.stdout.write(data),
  onStderr: (data) => process.stderr.write(data),
  onExit: (code) => console.log("Exited:", code),
  onScrollbackEnd: () => console.log("--- live output ---"),
});
On attach, the server replays the scrollback buffer (historical output), sends a scrollback-end marker, then streams live output.

Kill a Session

await sandbox.exec.kill(sessionId);
await sandbox.exec.kill(sessionId, 15); // SIGTERM
sandbox.commands is a deprecated alias for sandbox.exec. Use sandbox.exec in all new code.
CLI equivalent: oc exec. Full reference: TypeScript SDK · Python SDK · HTTP API.