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

# PTY REPL demo

> Create a PTY, send keystrokes, resize the terminal, and cleanly exit — the simplest PTY round-trip.

The simplest possible PTY example. Create a sandbox, open a PTY
session, send a few commands as raw keystrokes, resize the terminal
mid-session, and exit cleanly. Everything uses the **sync** API
and runs without a local TTY (no raw-mode needed).

## What you'll learn

* Opening a PTY with `sbx.pty.create()` and the `on_data` callback
* Sending keystrokes with `handle.send_stdin()`
* Resizing mid-session with `handle.resize(PtySize(...))`
* Waiting for a clean exit with `handle.wait()`

## Prerequisites

<Snippet file="snippets/env-setup.mdx" />

Also install the SDK if you haven't:

```bash theme={null}
pip install declaw
```

## Code walkthrough

Create a sandbox and open a PTY at 120x30. The `on_data` callback
writes every chunk straight to local stdout as it arrives:

```python theme={null}
from declaw import Sandbox
from declaw.sandbox.commands.models import PtySize

with Sandbox.create() as sbx:
    handle = sbx.pty.create(
        size=PtySize(cols=120, rows=30),
        on_data=lambda chunk: (
            sys.stdout.buffer.write(chunk),
            sys.stdout.buffer.flush(),
        ),
        timeout=60,
    )
```

Send a few commands. A short `sleep` between sends gives the shell
time to print output before the next command arrives:

```python theme={null}
    handle.send_stdin(b"echo hello-from-pty\n")
    handle.send_stdin(b"python3 -c 'import sys; print(sys.stdout.isatty())'\n")
    handle.send_stdin(b"stty size\n")
```

`isatty()` returns `True` because this is a real PTY, not a piped
exec. `stty size` prints `30 120` matching the size we requested.

Resize the terminal to 100x40 and verify:

```python theme={null}
    handle.resize(PtySize(cols=100, rows=40))
    handle.send_stdin(b"stty size\n")   # → 40 100
```

Exit the shell and collect the result:

```python theme={null}
    handle.send_stdin(b"exit\n")
    result = handle.wait(timeout=10)
    print(f"pty exited with code {result.exit_code}")
```

## Running it

```bash theme={null}
export DECLAW_API_KEY="your-api-key"
export DECLAW_DOMAIN="api.declaw.ai"
python cookbook/examples/pty-repl/main.py
```

## Expected output

```
sandbox: sbx_abc123
pty pid: 7

bash-5.1$ echo hello-from-pty
hello-from-pty
bash-5.1$ python3 -c 'import sys; print(sys.stdout.isatty())'
True
bash-5.1$ stty size
30 120
bash-5.1$ stty size
40 100
bash-5.1$ exit

[pty exited with code 0]
```

The key takeaway: the remote shell saw a real PTY (`isatty() = True`)
and `stty size` updated after `handle.resize()` without reconnecting.

## Full source

See `cookbook/examples/pty-repl/main.py` in the repo.
