Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions docs/reference/python-sdk.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,9 @@ Run a command synchronously via `sh -c`.
result = await sandbox.exec.run("npm test", cwd="/app")
```

### `await sandbox.exec.start(command, ...): str`
### `await sandbox.exec.start(command, ...): ExecSession`

Start a long-running command. Returns the **session ID** (not a session object).
Start a long-running command with streaming I/O. Returns an `ExecSession` — see the [full reference](/reference/python-sdk/exec#await-sandbox-exec-start-command).

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
Expand All @@ -305,14 +305,37 @@ Start a long-running command. Returns the **session ID** (not a session object).
| `env` | dict[str, str] | None | Environment variables |
| `cwd` | str | None | Working directory |
| `timeout` | int | None | Timeout in seconds |
| `max_run_after_disconnect` | int | None | Seconds to keep running after disconnect |
| `on_stdout` | Callable[[bytes], None] | None | Stdout callback |
| `on_stderr` | Callable[[bytes], None] | None | Stderr callback |
| `on_exit` | Callable[[int], None] | None | Exit callback |

```python
session_id = await sandbox.exec.start("node server.js", cwd="/app")
session = await sandbox.exec.start(
"node", args=["server.js"], cwd="/app",
on_stdout=lambda b: print(b.decode(), end=""),
)
exit_code = await session.done
```

<Note>
Python `exec.start()` returns a session ID string. There are no streaming callbacks, `ExecSession` object, or `maxRunAfterDisconnect`. For streaming, use the [WebSocket binary protocol](/reference/api#websocket-binary-protocol).
</Note>
### `await sandbox.exec.background(command, ...): ExecSession`

Alias for `start`. Same signature and return type.

### `await sandbox.exec.shell(cwd=None, env=None): Shell`

Open a stateful shell session whose `cwd`, env vars, and shell functions persist across `.run()` calls. Foreground-only. See the [full reference](/reference/python-sdk/exec#await-sandbox-exec-shell).

```python
sh = await sandbox.exec.shell(cwd="/app")
await sh.run("export NODE_ENV=test")
r = await sh.run("npm test")
await sh.close()
```

### `await sandbox.exec.attach(session_id, ...): ExecSession`

Reconnect to a running exec session over WebSocket, with the same streaming callbacks as `start`.

### `await sandbox.exec.list(): list[ExecSessionInfo]`

Expand All @@ -322,13 +345,6 @@ List all exec sessions.

Kill an exec session.

### Not Available in Python

- `exec.attach()` — reconnect to running session
- Streaming callbacks (`on_stdout`, `on_stderr`, `on_exit`)
- `ExecSession` object with `send_stdin()` and `done`
- `max_run_after_disconnect`

### ProcessResult

```python
Expand Down
121 changes: 112 additions & 9 deletions docs/reference/python-sdk/exec.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ result = await sandbox.exec.run("npm test", cwd="/app")

## `await sandbox.exec.start(command, ...)`

Start a long-running command. Returns the **session ID** (not a session object). [HTTP API →](/api-reference/exec/create-session)
Start a long-running command with streaming I/O. [HTTP API →](/api-reference/exec/create-session)

<ParamField body="command" type="str" required>
Command
Expand All @@ -57,16 +57,116 @@ Start a long-running command. Returns the **session ID** (not a session object).
Timeout in seconds
</ParamField>

**Returns:** `str` (session ID)
<ParamField body="max_run_after_disconnect" type="int">
Seconds to keep running after disconnect
</ParamField>

<ParamField body="on_stdout" type="Callable[[bytes], None]">
Stdout callback
</ParamField>

<ParamField body="on_stderr" type="Callable[[bytes], None]">
Stderr callback
</ParamField>

<ParamField body="on_exit" type="Callable[[int], None]">
Exit callback
</ParamField>

**Returns:** `ExecSession`

```python
session = await sandbox.exec.start(
"node", args=["server.js"], cwd="/app",
on_stdout=lambda b: print(b.decode(), end=""),
on_exit=lambda code: print(f"exited {code}"),
)
exit_code = await session.done
```

---

## `await sandbox.exec.background(command, ...)`

Alias for [`start`](#await-sandbox-exec-start-command). Same signature, same return type. Use when the intent is "run this in the background and observe it".

```python
server = await sandbox.exec.background("npm", args=["run", "dev"])
```

---

## `await sandbox.exec.shell(...)`

Open a stateful shell session. Subsequent `.run()` calls share the same bash process, so `cwd`, exported env vars, and shell functions persist — the ergonomics of a terminal tab.

Backed by a long-running `bash --noprofile --norc` session. Foreground-only: concurrent `.run()` raises `ShellBusyError`.

<ParamField body="cwd" type="str">
Initial working directory
</ParamField>

<ParamField body="env" type="dict[str, str]">
Initial environment variables
</ParamField>

**Returns:** `Shell`

```python
session_id = await sandbox.exec.start("node server.js", cwd="/app")
sh = await sandbox.exec.shell(cwd="/app")

await sh.run("npm install")
await sh.run("export NODE_ENV=test")
r = await sh.run("npm test", on_stdout=lambda b: print(b.decode(), end=""))
print(r.exit_code)

await sh.close()
```

### Shell

| Member | Type | Description |
| --- | --- | --- |
| `session_id` | `str` | Underlying exec session ID |
| `run(cmd, on_stdout=?, on_stderr=?)` | `ProcessResult` | Run a command, blocking until it exits |
| `close()` | `None` | Write `exit` and wait for bash to terminate |

<Note>
Python `exec.start()` returns a session ID string. There are no streaming callbacks, `ExecSession` object, or `max_run_after_disconnect`. For streaming, use the [WebSocket binary protocol](/reference/api#websocket-binary-protocol).
Per-call `cwd`, `env`, and `timeout` are intentionally not supported in v1. Use inline shell syntax (`cd /x && cmd`, `FOO=bar cmd`) — the shell state carries across calls.
</Note>

Errors:
- `ShellBusyError` — another `run()` is in flight (shell is foreground-only).
- `ShellClosedError` — bash has exited (explicit `close()`, a command ran `exit`, or the session dropped).

---

## `await sandbox.exec.attach(session_id, ...)`

Reconnect to a running exec session over WebSocket.

<ParamField body="session_id" type="str" required>
Session ID
</ParamField>

<ParamField body="on_stdout" type="Callable[[bytes], None]">
Stdout callback
</ParamField>

<ParamField body="on_stderr" type="Callable[[bytes], None]">
Stderr callback
</ParamField>

<ParamField body="on_exit" type="Callable[[int], None]">
Exit callback
</ParamField>

<ParamField body="on_scrollback_end" type="Callable[[], None]">
Scrollback replay done
</ParamField>

**Returns:** `ExecSession`

---

## `await sandbox.exec.list()`
Expand All @@ -85,12 +185,15 @@ Kill an exec session. [HTTP API →](/api-reference/exec/kill-session)

---

## Not Available in Python
## ExecSession

- `exec.attach()` — reconnect to running session
- Streaming callbacks (`on_stdout`, `on_stderr`, `on_exit`)
- `ExecSession` object with `send_stdin()` and `done`
- `max_run_after_disconnect`
| Member | Type | Description |
| --- | --- | --- |
| `session_id` | `str` | Session ID |
| `done` | `asyncio.Future[int]` | Resolves with exit code |
| `send_stdin(data)` | coroutine | Send input (`str` or `bytes`) |
| `kill(signal=9)` | coroutine | Kill process |
| `close()` | coroutine | Detach WebSocket (process keeps running) |

---

Expand Down
15 changes: 15 additions & 0 deletions docs/reference/typescript-sdk.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,21 @@ const session = await sandbox.exec.start("node server.js", {
});
```

### `sandbox.exec.background(command, opts?): Promise<ExecSession>`

Alias for `start`. Same signature and return type — use when the intent is "run this in the background and observe it".

### `sandbox.exec.shell(opts?): Promise<Shell>`

Open a stateful shell session whose `cwd`, env vars, and shell functions persist across `.run()` calls. Foreground-only. See the [full reference](/reference/typescript-sdk/exec#sandbox-exec-shell-opts).

```typescript
const sh = await sandbox.exec.shell({ cwd: "/app" });
await sh.run("export NODE_ENV=test");
const r = await sh.run("npm test");
await sh.close();
```

### `sandbox.exec.attach(sessionId, opts?): Promise<ExecSession>`

Reconnect to a running exec session.
Expand Down
67 changes: 67 additions & 0 deletions docs/reference/typescript-sdk/exec.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,73 @@ const session = await sandbox.exec.start("node server.js", {

---

## `sandbox.exec.background(command, opts?)`

Alias for [`start`](#sandbox-exec-start-command-opts). Same options, same return type. Use when the intent is "run this in the background and observe it" — more discoverable than `start` for that case.

```typescript
const server = await sandbox.exec.background("npm", {
args: ["run", "dev"],
onStdout: (data) => process.stdout.write(data),
});
```

---

## `sandbox.exec.shell(opts?)`

Open a stateful shell session. Subsequent `.run()` calls share the same bash process, so `cwd`, exported env vars, and shell functions persist — the ergonomics of a terminal tab.

Backed by a long-running `bash --noprofile --norc` session. Foreground-only: concurrent `.run()` rejects with `ShellBusyError`. Use [`background`](#sandbox-exec-background-command-opts) for fire-and-forget processes.

<ParamField body="cwd" type="string">
Initial working directory
</ParamField>

<ParamField body="env" type="Record<string, string>">
Initial environment variables
</ParamField>

**Returns:** `Promise<Shell>`

```typescript
const sh = await sandbox.exec.shell({ cwd: "/app" });

await sh.run("npm install");
await sh.run("export NODE_ENV=test");
const r = await sh.run("npm test", {
onStdout: (b) => process.stdout.write(b),
});
console.log(r.exitCode);

await sh.close();
```

### Shell

| Member | Type | Description |
| --- | --- | --- |
| `sessionId` | `string` | Underlying exec session ID |
| `run(cmd, opts?)` | `Promise<ProcessResult>` | Run a command, blocking until it exits |
| `close()` | `Promise<void>` | Write `exit` and wait for bash to terminate |

### ShellRunOpts

| Parameter | Type | Description |
| --- | --- | --- |
| `onStdout` | `(data: Uint8Array) => void` | Per-call stdout callback |
| `onStderr` | `(data: Uint8Array) => void` | Per-call stderr callback |

<Note>
Per-call `cwd`, `env`, and `timeout` are intentionally not supported in v1. Use inline shell syntax (`cd /x && cmd`, `FOO=bar cmd`) — the shell state carries across calls. Timeouts will land once we have a "signal foreground job" primitive.
</Note>

Errors:
- `ShellBusyError` — another `run()` is in flight (shell is foreground-only).
- `ShellClosedError` — bash has exited (explicit `close()`, a command ran `exit`, or the session dropped).

---

## `sandbox.exec.attach(sessionId, opts?)`

Reconnect to a running exec session.
Expand Down
Loading