Skip to main content
import { Sandbox } from '@declaw/sdk';
import type { CommandResult, ProcessInfo, RunOpts, RunStreamOpts } from '@declaw/sdk';
sbx.commands is the Commands instance available on every Sandbox. It provides methods to run commands, stream output, and manage processes.

sbx.commands.run()

Run a command in the sandbox. Returns a CommandResult when run in the foreground (default), or a CommandHandle when background: true.
// Foreground — block until complete
const result: CommandResult = await sbx.commands.run('echo hello');
console.log(result.stdout);   // "hello\n"
console.log(result.exitCode); // 0

// Background — return immediately
const handle = await sbx.commands.run('sleep 30', { background: true });
console.log('PID:', handle.pid);
cmd
string
required
Shell command to execute inside the sandbox.
opts
RunOpts
Optional run configuration.

RunOpts

background
boolean
default:"false"
When true, returns a CommandHandle immediately. When false (default), blocks and returns CommandResult.
envs
Record<string, string>
Environment variables for the command.
user
string
default:"'user'"
Unix user to run the command as.
cwd
string
Working directory.
timeout
number
default:"60"
Command execution timeout in seconds.
requestTimeout
number
Per-request HTTP timeout in milliseconds.
onStdout
(line: string) => void
Callback invoked for each stdout line after the command completes (foreground only). For real-time output, use runStream().
onStderr
(line: string) => void
Callback invoked for each stderr line after the command completes.
Returns Promise<CommandResult> (foreground) or Promise<CommandHandle> (background)

sbx.commands.runStream()

Run a command with real-time SSE streaming. Callbacks are invoked as each chunk of output arrives via Server-Sent Events.
const lines: string[] = [];

const result = await sbx.commands.runStream(
  'for i in $(seq 1 50); do echo "line $i"; sleep 0.02; done',
  {
    onStdout: (chunk) => {
      process.stdout.write(chunk);
      lines.push(chunk);
    },
    onStderr: (chunk) => process.stderr.write(chunk),
  },
);
console.log('Exit code:', result.exitCode);
cmd
string
required
Shell command to execute.
opts
RunStreamOpts
Optional streaming configuration.

RunStreamOpts

envs
Record<string, string>
Environment variables for the command.
user
string
default:"'user'"
Unix user to run as.
cwd
string
Working directory.
timeout
number
default:"60"
Command execution timeout in seconds.
onStdout
(line: string) => void
Called in real-time for each stdout chunk as it arrives.
onStderr
(line: string) => void
Called in real-time for each stderr chunk as it arrives.
Returns Promise<CommandResult> with the accumulated stdout and stderr.

sbx.commands.list()

List all running processes in the sandbox.
const processes: ProcessInfo[] = await sbx.commands.list();
for (const p of processes) {
  console.log(p.pid, p.cmd);
}
requestTimeout
number
Per-request HTTP timeout in milliseconds.
Returns Promise<ProcessInfo[]>

sbx.commands.kill()

Send SIGKILL to a process by PID.
const killed = await sbx.commands.kill(1234);
pid
number
required
Process ID to kill.
requestTimeout
number
Per-request HTTP timeout in milliseconds.
Returns Promise<boolean>true if killed, false if already dead.

sbx.commands.sendStdin()

Write data to the stdin of a running process.
const handle = await sbx.commands.run('cat', { background: true });
await sbx.commands.sendStdin(handle.pid, 'hello\n');
await sbx.commands.sendStdin(handle.pid, 'world\n');
pid
number
required
Process ID of the running command.
data
string
required
Data to write to stdin. Include \n for newlines.
requestTimeout
number
Per-request HTTP timeout in milliseconds.
Returns Promise<void>

sbx.commands.connect()

Create a CommandHandle for an already-running process by PID without making an API call.
const handle = sbx.commands.connect(5678);
const result = await handle.wait();
pid
number
required
Process ID of the running command.
Returns CommandHandle (synchronous, no API call)

CommandHandle

Returned by commands.run({ background: true }) and commands.connect().
const handle = await sbx.commands.run('python3 train.py', { background: true });
console.log('PID:', handle.pid);

const result = await handle.wait({
  onStdout: (line) => console.log('>', line),
  onStderr: (line) => console.error('!', line),
});
console.log('Finished with exit code:', result.exitCode);

handle.wait()

Wait for the background command to complete.
opts.onStdout
(line: string) => void
Called for each stdout line.
opts.onStderr
(line: string) => void
Called for each stderr line.
Returns Promise<CommandResult>. Throws CommandExitError if exit code is non-zero.

handle.kill()

Kill the process. Returns Promise<boolean>

handle.disconnect()

Disconnect from the handle (currently a no-op; reserved for future WebSocket support). Returns void

handle.pid

Type number — the process ID.

Data models

CommandResult

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

ProcessInfo

interface ProcessInfo {
  pid: number;
  cmd: string;
  isPty: boolean;
  envs: Record<string, string>;
}

CommandWaitOpts

interface CommandWaitOpts {
  onStdout?: (line: string) => void;
  onStderr?: (line: string) => void;
}

Examples

Run a Node.js script

const result = await sbx.commands.run(
  'node -e "console.log(process.version)"',
  { timeout: 10 },
);
console.log(result.stdout.trim());

Run with environment variables

const result = await sbx.commands.run('echo $SECRET', {
  envs: { SECRET: 'supersecret' },
});

Background process with stdin

const handle = await sbx.commands.run(
  'node -e "process.stdin.on(\'data\', d => process.stdout.write(d.toString().toUpperCase()))"',
  { background: true },
);

await new Promise(r => setTimeout(r, 100)); // allow process to start
await sbx.commands.sendStdin(handle.pid, 'hello\n');
await sbx.commands.kill(handle.pid);

Stream long-running output

const chunks: string[] = [];
const result = await sbx.commands.runStream(
  'for i in $(seq 1 5); do echo "step $i"; sleep 0.1; done',
  { onStdout: (chunk) => chunks.push(chunk) },
);
console.log(`Collected ${chunks.length} chunks, exit code ${result.exitCode}`);