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

# PTY

A PTY (pseudo-terminal) is a virtual terminal interface that lets programs interact with a shell as if connected to a real terminal. Use the `sandbox.pty` module to create interactive terminal sessions that run commands, accept input, and can be resized while running — useful for REPLs and debuggers, interactive CLIs that prompt for input, and long-running processes you need to monitor.

<Note>
  **Note:** A PTY is identified by its process ID (`pid`), returned from `create()` on the handle. Pass that `pid` to send input, resize, connect, and kill. Output is delivered to a callback as raw bytes.
</Note>

| Operation  | JavaScript / TypeScript            | Python                              |
| ---------- | ---------------------------------- | ----------------------------------- |
| Create     | `sandbox.pty.create(opts)`         | `sandbox.pty.create(size, ...)`     |
| Connect    | `sandbox.pty.connect(pid, opts?)`  | `sandbox.pty.connect(pid, ...)`     |
| Send input | `sandbox.pty.sendInput(pid, data)` | `sandbox.pty.send_stdin(pid, data)` |
| Resize     | `sandbox.pty.resize(pid, size)`    | `sandbox.pty.resize(pid, size)`     |
| Kill       | `sandbox.pty.kill(pid)`            | `sandbox.pty.kill(pid)`             |

***

## Create a PTY

Create a PTY and receive its output through a callback. It returns a handle whose `pid` identifies the PTY.

| Option                  | Type                             | Description                                                            |
| ----------------------- | -------------------------------- | ---------------------------------------------------------------------- |
| `cols` / `rows`         | number                           | Terminal dimensions (Python: `PtySize(cols=…, rows=…)`)                |
| `onData` (JS)           | (data: Uint8Array) => void       | Callback for PTY output. Python delivers output via `wait(on_pty=...)` |
| `user`                  | string (optional)                | User to run the PTY as                                                 |
| `cwd`                   | string (optional)                | Working directory                                                      |
| `envs`                  | object / dict (optional)         | Environment variables (`TERM`, `LANG`, `LC_ALL` are defaulted)         |
| `timeoutMs` / `timeout` | number (default 60000 ms / 60 s) | PTY timeout; JS uses ms, Python uses seconds                           |

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Novita } from 'novita-sandbox'

  const novita = new Novita()
  const sandbox = await novita.sandbox.create()

  const pty = await sandbox.pty.create({
    cols: 120,
    rows: 30,
    cwd: '/home/user',
    envs: { TERM: 'xterm-256color' },
    onData: (data) => {
      process.stdout.write(new TextDecoder().decode(data))
    },
  })

  console.log('PTY pid:', pty.pid)
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox import Novita
  from novita_sandbox.core.sandbox.commands.command_handle import PtySize

  novita = Novita()
  sandbox = novita.sandbox.create()

  def on_pty(data: bytes):
      print(data.decode('utf-8', errors='replace'), end='')

  # PtySize takes keyword args cols / rows
  pty = sandbox.pty.create(PtySize(cols=120, rows=30), cwd='/home/user', envs={'TERM': 'xterm-256color'})
  print('PTY pid:', pty.pid)
  ```
</CodeGroup>

***

## Send input

Send input to a running PTY by its `pid`. The data is raw bytes.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  const enc = new TextEncoder()
  await sandbox.pty.sendInput(pty.pid, enc.encode('echo hello\n'))
  await sandbox.pty.sendInput(pty.pid, enc.encode('exit\n'))
  ```

  ```python Python icon="python" theme={"system"}
  sandbox.pty.send_stdin(pty.pid, b'echo hello\n')
  sandbox.pty.send_stdin(pty.pid, b'exit\n')
  ```
</CodeGroup>

***

## Resize a PTY

Call `resize` when the terminal window changes size.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  await sandbox.pty.resize(pty.pid, { cols: 150, rows: 40 })
  ```

  ```python Python icon="python" theme={"system"}
  sandbox.pty.resize(pty.pid, PtySize(cols=150, rows=40))
  ```
</CodeGroup>

***

## Connect to a running PTY

Connect to a PTY that is already running by its `pid`. You can obtain running processes with `sandbox.commands.list()`. The returned handle receives further output through the callback.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  const handle = await sandbox.pty.connect(pty.pid, {
    onData: (data) => process.stdout.write(new TextDecoder().decode(data)),
  })
  ```

  ```python Python icon="python" theme={"system"}
  handle = sandbox.pty.connect(pty.pid)
  ```
</CodeGroup>

***

## Kill a PTY

`kill` terminates the PTY with `SIGKILL`. It returns `true` if the PTY was killed, or `false` if no PTY with that `pid` was found.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  const killed = await sandbox.pty.kill(pty.pid)
  console.log('killed:', killed)

  await sandbox.kill()
  ```

  ```python Python icon="python" theme={"system"}
  killed = sandbox.pty.kill(pty.pid)
  print('killed:', killed)

  sandbox.kill()
  ```
</CodeGroup>

***

## Interactive example

Create a PTY, send an interactive command that prompts for input, then wait for it to finish and read the exit code. In Python, `wait(on_pty=...)` streams output to the callback and returns the result.

```python Python icon="python" theme={"system"}
from novita_sandbox import Novita
from novita_sandbox.core.sandbox.commands.command_handle import PtySize

novita = Novita()
sandbox = novita.sandbox.create()

output = []

def on_pty(data: bytes):
    output.append(data.decode('utf-8', errors='replace'))

terminal = sandbox.pty.create(PtySize(cols=80, rows=24), envs={'ABC': '123'}, cwd='/')

# Send a command and exit
sandbox.pty.send_stdin(terminal.pid, b'echo $ABC\nexit\n')

# Stream output and wait for completion
result = terminal.wait(on_pty=on_pty)
print('exit code:', result.exit_code)
print(''.join(output))

sandbox.kill()
```
