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

# Stdio

> Python SDK reference for sandbox.stdio — start interactive subprocesses with bidirectional stdin/stdout/stderr.

The Python SDK exposes stdio through `sandbox.stdio`. Use
`Stdio.start()` to launch a process with an open stdin pipe, then
send data, receive output, and close stdin or kill the process.

For conceptual background see the
[Stdio feature overview](/features/stdio).

## `sandbox.stdio.start(...)` → `StdioProcess`

Start a subprocess with an open stdin pipe. The sandbox runs the
command and returns a [`StdioProcess`](#stdioprocess) handle.

```python theme={null}
proc = sandbox.stdio.start(
    "cat",
    envs={"FOO": "bar"},               # extra env vars (optional)
    user="user",                        # shell user (default "user")
    cwd="/workspace",                   # working directory (optional)
    on_stdout=lambda b: print(b),       # streaming stdout callback (optional)
    on_stderr=lambda b: print(b),       # streaming stderr callback (optional)
    request_timeout=None,               # httpx timeout for the POST
)
```

### Parameters

| Name              | Type                              | Default      | Description                                                                |
| ----------------- | --------------------------------- | ------------ | -------------------------------------------------------------------------- |
| `cmd`             | `str`                             | *(required)* | Shell command to execute.                                                  |
| `envs`            | `dict[str, str] \| None`          | `None`       | Environment variables merged into the process env.                         |
| `user`            | `str`                             | `"user"`     | User the process runs as.                                                  |
| `cwd`             | `str \| None`                     | `None`       | Working directory.                                                         |
| `on_stdout`       | `Callable[[bytes], None] \| None` | `None`       | If provided, a background reader thread calls this for every stdout chunk. |
| `on_stderr`       | `Callable[[bytes], None] \| None` | `None`       | Same, for stderr.                                                          |
| `request_timeout` | `float \| None`                   | `None`       | httpx timeout for the start POST only.                                     |

### Returns

A [`StdioProcess`](#stdioprocess).

## `StdioProcess`

Handle for an interactive subprocess with stdin pipe. Provides
bidirectional I/O: send data via `send_stdin`, receive output via
callbacks or iteration, and manage the process lifecycle.

### Properties

* `proc.cmd_id: str` — server-assigned command identifier.
* `proc.exit_code: int | None` — `None` while the process is running;
  set once the exit SSE event arrives.

### Methods

#### `proc.send_stdin(data, request_timeout=None) -> None`

Send data to the process's stdin. Accepts `bytes` or `str`; `str` is
UTF-8 encoded.

```python theme={null}
proc.send_stdin("hello\n")
proc.send_stdin(b"\x04")  # Ctrl-D
```

#### `proc.close_stdin(request_timeout=None) -> None`

Close the process's stdin pipe, sending EOF. The process sees
end-of-file on its stdin.

```python theme={null}
proc.close_stdin()
```

#### `proc.kill(request_timeout=None) -> bool`

Terminate the process. Returns `True` if the process existed at the
time of the call.

#### `proc.wait(timeout=None) -> StdioResult`

Block until the process exits. If the process was started with
callbacks, this joins the background reader thread. Otherwise it
drains the SSE stream inline, discarding output.

```python theme={null}
result = proc.wait(timeout=30)
print(result.exit_code)
```

#### `proc.stream(on_stdout=None, on_stderr=None) -> StdioResult`

Block until the process exits, invoking callbacks for each output
chunk. Use this when you didn't provide callbacks at start time but
want to consume output.

```python theme={null}
proc = sandbox.stdio.start("sh -c 'echo hi; echo err >&2'")
result = proc.stream(
    on_stdout=lambda d: print("out:", d),
    on_stderr=lambda d: print("err:", d),
)
```

Raises `RuntimeError` if a background reader is already running (i.e.
callbacks were passed to `start()`). Use `wait()` in that case.

### Iterator protocol

`StdioProcess` is iterable when no background reader is active. Each
iteration yields a `(stream_type, data)` tuple where `stream_type` is
`"stdout"` or `"stderr"` and `data` is `bytes`.

```python theme={null}
proc = sandbox.stdio.start("sh -c 'echo alpha; echo beta >&2; echo gamma'")
for stream_type, data in proc:
    print(f"[{stream_type}] {data.decode().strip()}")
# [stdout] alpha
# [stderr] beta
# [stdout] gamma
```

Use the iterator **or** callbacks, not both — they consume the same
stream.

## `StdioResult`

```python theme={null}
@dataclass
class StdioResult:
    exit_code: int
```

Int-coercible — `int(result)` and `result == 0` both work.

## Threading notes

* The `on_stdout` / `on_stderr` callbacks run on a background daemon
  thread. Don't do long blocking work inside them.
* `send_stdin`, `close_stdin`, `kill` are safe to call from any thread.
* `wait()` is synchronous. For async code, `AsyncSandbox` provides an
  equivalent `stdio` module with coroutine-based callbacks (same method
  names).
