> ## Documentation Index
> Fetch the complete documentation index at: https://docs.declaw.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Commands

> Run, stream, list, kill, and interact with processes using sandbox.commands in the TypeScript SDK.

```typescript theme={null}
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`.

```typescript theme={null}
// 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);
```

<ParamField body="cmd" type="string" required>
  Shell command to execute inside the sandbox.
</ParamField>

<ParamField body="opts" type="RunOpts">
  Optional run configuration.
</ParamField>

### `RunOpts`

<ParamField body="background" type="boolean" default="false">
  When `true`, returns a `CommandHandle` immediately. When `false` (default),
  blocks and returns `CommandResult`.
</ParamField>

<ParamField body="envs" type="Record<string, string>">
  Environment variables for the command.
</ParamField>

<ParamField body="user" type="string" default="'user'">
  Unix user to run the command as.
</ParamField>

<ParamField body="cwd" type="string">
  Working directory.
</ParamField>

<ParamField body="timeout" type="number" default="60">
  Command execution timeout in seconds.
</ParamField>

<ParamField body="requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

<ParamField body="onStdout" type="(line: string) => void">
  Callback invoked for each stdout line **after** the command completes
  (foreground only). For real-time output, use `runStream()`.
</ParamField>

<ParamField body="onStderr" type="(line: string) => void">
  Callback invoked for each stderr line after the command completes.
</ParamField>

**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.

```typescript theme={null}
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);
```

<ParamField body="cmd" type="string" required>
  Shell command to execute.
</ParamField>

<ParamField body="opts" type="RunStreamOpts">
  Optional streaming configuration.
</ParamField>

### `RunStreamOpts`

<ParamField body="envs" type="Record<string, string>">
  Environment variables for the command.
</ParamField>

<ParamField body="user" type="string" default="'user'">
  Unix user to run as.
</ParamField>

<ParamField body="cwd" type="string">
  Working directory.
</ParamField>

<ParamField body="timeout" type="number" default="60">
  Command execution timeout in seconds.
</ParamField>

<ParamField body="onStdout" type="(line: string) => void">
  Called in real-time for each stdout chunk as it arrives.
</ParamField>

<ParamField body="onStderr" type="(line: string) => void">
  Called in real-time for each stderr chunk as it arrives.
</ParamField>

**Returns** `Promise<CommandResult>` with the accumulated stdout and stderr.

***

## `sbx.commands.list()`

List all running processes in the sandbox.

```typescript theme={null}
const processes: ProcessInfo[] = await sbx.commands.list();
for (const p of processes) {
  console.log(p.pid, p.cmd);
}
```

<ParamField body="requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<ProcessInfo[]>`

***

## `sbx.commands.kill()`

Send SIGKILL to a process by PID.

```typescript theme={null}
const killed = await sbx.commands.kill(1234);
```

<ParamField body="pid" type="number" required>
  Process ID to kill.
</ParamField>

<ParamField body="requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<boolean>` — `true` if killed, `false` if already dead.

***

## `sbx.commands.sendStdin()`

Write data to the stdin of a running process.

```typescript theme={null}
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');
```

<ParamField body="pid" type="number" required>
  Process ID of the running command.
</ParamField>

<ParamField body="data" type="string" required>
  Data to write to stdin. Include `\n` for newlines.
</ParamField>

<ParamField body="requestTimeout" type="number">
  Per-request HTTP timeout in milliseconds.
</ParamField>

**Returns** `Promise<void>`

***

## `sbx.commands.connect()`

Create a `CommandHandle` for an already-running process by PID without making an API call.

```typescript theme={null}
const handle = sbx.commands.connect(5678);
const result = await handle.wait();
```

<ParamField body="pid" type="number" required>
  Process ID of the running command.
</ParamField>

**Returns** `CommandHandle` (synchronous, no API call)

***

## CommandHandle

Returned by `commands.run({ background: true })` and `commands.connect()`.

```typescript theme={null}
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.

<ParamField body="opts.onStdout" type="(line: string) => void">
  Called for each stdout line.
</ParamField>

<ParamField body="opts.onStderr" type="(line: string) => void">
  Called for each stderr line.
</ParamField>

**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`

```typescript theme={null}
interface CommandResult {
  stdout: string;
  stderr: string;
  exitCode: number;
}
```

### `ProcessInfo`

```typescript theme={null}
interface ProcessInfo {
  pid: number;
  cmd: string;
  isPty: boolean;
  envs: Record<string, string>;
}
```

### `CommandWaitOpts`

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

***

## Examples

### Run a Node.js script

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

### Run with environment variables

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

### Background process with stdin

```typescript theme={null}
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

```typescript theme={null}
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}`);
```
