> ## 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 commands inside sandboxes: blocking execution, streaming output, background processes, and stdin.

The `commands` module on a sandbox lets you run shell commands inside the sandbox. Commands have access to the full Linux userspace, can read and write the sandbox filesystem, and respect environment variables set at the sandbox or command level.

## Run a command (blocking)

`run()` executes the command and waits for it to complete, then returns a `CommandResult`.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    result = sbx.commands.run("echo 'Hello from Declaw!'")
    print(result.stdout)    # Hello from Declaw!
    print(result.stderr)    # (empty)
    print(result.exit_code) # 0
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await sbx.commands.run("echo 'Hello from Declaw!'");
    console.log(result.stdout);   // Hello from Declaw!
    console.log(result.exitCode); // 0
    ```
  </Tab>
</Tabs>

### CommandResult model

| Field       | Type  | Description                           |
| ----------- | ----- | ------------------------------------- |
| `stdout`    | `str` | Full standard output from the command |
| `stderr`    | `str` | Full standard error from the command  |
| `exit_code` | `int` | Process exit code (0 = success)       |

### Run options

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    result = sbx.commands.run(
        "python3 script.py",
        envs={"PYTHONPATH": "/opt/mylib"},   # per-command env vars
        cwd="/workspace",                     # working directory
        user="root",                          # run as user
        timeout=30,                           # seconds before TimeoutException
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await sbx.commands.run('python3 script.py', {
      envs: { PYTHONPATH: '/opt/mylib' },
      cwd: '/workspace',
      user: 'root',
      timeout: 30,
    });
    ```
  </Tab>
</Tabs>

## Run with output callbacks

`run()` accepts `on_stdout`/`on_stderr` callbacks that are invoked after the command completes, iterating over the collected output lines. Each callback receives a plain `str`.

<Note>
  For true real-time streaming as the command produces output, use `run_stream()` / `runStream()` instead.
</Note>

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    result = sbx.commands.run(
        "python3 -c \"import time; [print(i, flush=True) or time.sleep(0.1) for i in range(5)]\"",
        on_stdout=lambda line: print("OUT:", line),
        on_stderr=lambda line: print("ERR:", line),
    )
    # OUT: 0
    # OUT: 1
    # OUT: 2
    # OUT: 3
    # OUT: 4
    print("Exit:", result.exit_code)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await sbx.commands.run(
      'for i in 1 2 3 4 5; do echo $i; sleep 0.1; done',
      {
        onStdout: (line) => console.log('OUT:', line),
        onStderr: (line) => console.error('ERR:', line),
      },
    );
    console.log('Exit:', result.exitCode);
    ```
  </Tab>
</Tabs>

## Background processes

Pass `background=True` to start a long-running process and get a `CommandHandle` back immediately.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    # Start a background HTTP server
    handle = sbx.commands.run(
        "python3 -m http.server 8080",
        background=True,
    )
    print(handle.pid)  # 42

    # Do other work...
    sbx.commands.run("curl http://localhost:8080")

    # Wait for it to finish
    result = handle.wait()

    # Or kill it explicitly
    sbx.commands.kill(handle.pid)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const handle = await sbx.commands.run('python3 -m http.server 8080', {
      background: true,
    });
    console.log(handle.pid);

    // Kill when done
    await sbx.commands.kill(handle.pid);
    ```
  </Tab>
</Tabs>

### CommandHandle

| Field/Method | Description                                                                                                                        |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| `pid`        | Process identifier within the sandbox                                                                                              |
| `wait()`     | Block until the process finishes; returns `CommandResult`. Raises `CommandExitException`/`CommandExitError` on non-zero exit code. |

## List running commands

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    processes = sbx.commands.list()
    for p in processes:
        print(p.pid, p.cmd, p.is_pty)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const processes = await sbx.commands.list();
    for (const p of processes) {
      console.log(p.pid, p.cmd, p.isPty);
    }
    ```
  </Tab>
</Tabs>

### ProcessInfo model

| Field              | Type              | Description                             |
| ------------------ | ----------------- | --------------------------------------- |
| `pid`              | `int`             | Process ID inside the sandbox           |
| `cmd`              | `str`             | Command string that was run             |
| `is_pty` / `isPty` | `bool`            | Whether the process is running in a PTY |
| `envs`             | `dict` / `Record` | Environment variables for the process   |

## Send stdin to a running process

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    handle = sbx.commands.run("cat", background=True)

    sbx.commands.send_stdin(handle.pid, "line one\n")
    sbx.commands.send_stdin(handle.pid, "line two\n")

    # Close stdin by killing, or wait if process exits naturally
    sbx.commands.kill(handle.pid)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const handle = await sbx.commands.run('cat', { background: true });

    await sbx.commands.sendStdin(handle.pid, 'line one\n');
    await sbx.commands.sendStdin(handle.pid, 'line two\n');

    await sbx.commands.kill(handle.pid);
    ```
  </Tab>
</Tabs>

## Kill a command

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    sbx.commands.kill(pid=42)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    await sbx.commands.kill(42);
    ```
  </Tab>
</Tabs>

## Wait for a command by PID

If you lost the `CommandHandle` reference, reconnect using `connect()` and call `wait()`.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    handle = sbx.commands.connect(pid=42)
    result = handle.wait()
    print(result.exit_code)
    ```
  </Tab>
</Tabs>

## Error handling

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from declaw import CommandExitException, TimeoutException

    try:
        result = sbx.commands.run("exit 1")
    except CommandExitException as e:
        print(f"Command failed with exit code {e.exit_code}")
        print(e.stderr)

    try:
        result = sbx.commands.run("sleep 100", timeout=5)
    except TimeoutException:
        print("Command timed out")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import { CommandExitError, TimeoutError } from '@declaw/sdk';

    try {
      await sbx.commands.run('exit 1');
    } catch (e) {
      if (e instanceof CommandExitError) {
        console.log(`Failed with exit code ${e.exitCode}`);
      }
    }
    ```
  </Tab>
</Tabs>

<Note>
  `commands.run()` does **not** throw on non-zero exit codes — check `result.exit_code` yourself. However, `handle.wait()` (on background processes) **always** throws `CommandExitException` / `CommandExitError` on non-zero exit codes.
</Note>

## Multi-language execution

The default sandbox template includes Python 3, Node.js, Go, and standard shell utilities.

```python theme={null}
# Python
r = sbx.commands.run("python3 -c 'print(2+2)'")
print(r.stdout)  # 4

# Node.js
r = sbx.commands.run("node -e 'console.log(2+2)'")
print(r.stdout)  # 4

# Go
sbx.files.write("/tmp/main.go", """
package main
import "fmt"
func main() { fmt.Println(2+2) }
""")
r = sbx.commands.run("go run /tmp/main.go")
print(r.stdout)  # 4
```
