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

# Interactive PTY Terminal via WebSocket

> GET /v1/capsules/{id}/pty — WebSocket endpoint for interactive PTY sessions. Supports starting, reconnecting, resizing, and killing terminal sessions.

The PTY endpoint gives you a full interactive terminal inside a capsule. Unlike the exec and stream endpoints, PTY sessions allocate a pseudo-terminal device — the same infrastructure that powers SSH and terminal emulators. This means programs that rely on a TTY (interactive shells, editors like `vim`, full-screen CLI apps) behave correctly.

Sessions persist across WebSocket disconnections. If your connection drops, the process keeps running inside the capsule and you can reconnect using the session tag.

## Endpoint

```
GET https://app.wrenn.dev/api/v1/capsules/{id}/pty
```

Upgrade this request to a WebSocket by including the standard `Upgrade: websocket` headers.

## Authentication

<ParamField header="X-API-Key" type="string" required>
  Your team's API key.
</ParamField>

## Path parameters

<ParamField path="id" type="string" required>
  The capsule ID.
</ParamField>

## WebSocket protocol

### Client messages — starting a session

Send this as the first message to start a new PTY session:

```json theme={null}
{
  "type": "start",
  "cmd": "/bin/bash",
  "args": [],
  "cols": 80,
  "rows": 24,
  "envs": {"TERM": "xterm-256color"},
  "cwd": "/home/user",
  "user": "user"
}
```

| Field  | Type      | Required | Default       | Description                             |
| ------ | --------- | -------- | ------------- | --------------------------------------- |
| `type` | string    | Yes      | —             | Must be `"start"`.                      |
| `cmd`  | string    | No       | `"/bin/bash"` | Command to run as the terminal process. |
| `args` | string\[] | No       | `[]`          | Arguments to pass to the command.       |
| `cols` | integer   | No       | `80`          | Terminal width in columns.              |
| `rows` | integer   | No       | `24`          | Terminal height in rows.                |
| `envs` | object    | No       | `{}`          | Additional environment variables.       |
| `cwd`  | string    | No       | —             | Working directory for the process.      |
| `user` | string    | No       | —             | User to run the process as.             |

### Client messages — reconnecting

To reconnect to an existing PTY session, send the tag you received in the `started` server message:

```json theme={null}
{
  "type": "connect",
  "tag": "pty-abc123de"
}
```

### Client messages — during a session

Once the session is established (after receiving `started` from the server), you can send:

**Input** — keystrokes or pasted text, base64-encoded:

```json theme={null}
{
  "type": "input",
  "data": "<base64-encoded bytes>"
}
```

**Resize** — when the terminal window changes size:

```json theme={null}
{
  "type": "resize",
  "cols": 120,
  "rows": 40
}
```

**Kill** — terminate the terminal process:

```json theme={null}
{
  "type": "kill"
}
```

### Server messages

| `type`    | Fields                           | When sent                                                         |
| --------- | -------------------------------- | ----------------------------------------------------------------- |
| `started` | `tag: string`, `pid: integer`    | Session started. Save `tag` to reconnect later.                   |
| `output`  | `data: string`                   | Terminal output, base64-encoded. Decode before rendering.         |
| `exit`    | `exit_code: integer`             | Terminal process exited.                                          |
| `error`   | `data: string`, `fatal: boolean` | An error occurred. When `fatal` is `true`, the connection closes. |
| `ping`    | —                                | Keepalive from the server; no response required.                  |

```json theme={null}
{"type": "started", "tag": "pty-abc123de", "pid": 42}
{"type": "output", "data": "YmFzaC01LjIkIA=="}
{"type": "exit", "exit_code": 0}
```

<Note>
  All PTY data — both input you send and output you receive — is base64-encoded. Raw terminal bytes include ANSI escape sequences and control codes that are not valid UTF-8. Decode the `data` field before passing it to your terminal renderer.
</Note>

<Note>
  PTY sessions survive WebSocket disconnections. The process keeps running in the capsule. Save the `tag` from the `started` message and use `{"type": "connect", "tag": "..."}` to rejoin a session after a disconnect.
</Note>

## Python SDK

The SDK wraps the WebSocket protocol and decodes base64 output automatically. Iterate over the session directly to receive events.

```python theme={null}
import sys
from wrenn import Capsule

with Capsule(wait=True) as capsule:
    with capsule.pty(cmd="/bin/bash", cols=120, rows=40) as term:
        # Send input as raw bytes
        term.write(b"ls -la\n")

        # Iterate events
        for event in term:
            if event.type == "output":
                sys.stdout.buffer.write(event.data)
            elif event.type == "exit":
                break

# Reconnect to an existing session using its tag
saved_tag = term.tag
with capsule.pty_connect(saved_tag) as term:
    term.write(b"echo reconnected\n")
    for event in term:
        if event.type == "output":
            sys.stdout.buffer.write(event.data)
        elif event.type == "exit":
            break
```

## Errors

| Status | Meaning                                                                   |
| ------ | ------------------------------------------------------------------------- |
| `404`  | Capsule not found or does not belong to your team.                        |
| `409`  | Capsule is not in the `running` state. Start or resume the capsule first. |
