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

# PTY Sessions

> Create, reconnect, resize, and kill interactive terminal sessions.

PTY sessions run over the machine WebSocket channel and also expose REST helpers
for listing, resizing, and killing sessions.
Idle PTY streams remain connected while the machine is running. A WebSocket
close without a `pty_exited` message is reported as a transport disconnect.
Session IDs are scoped to the current running machine execution; after
hibernate/resume, create a new PTY session.

PTY sessions are created over the machine WebSocket channel
(`/v1/machines/{id}/ws`); the SDKs and CLI manage that connection. List, resize,
and kill also have REST endpoints (see [Manage sessions](#manage-sessions)).

## Create a session

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  session = machine.pty.create_session(cols=100, rows=30, cwd="/workspace")
  chunks = []

  session.send_input("pwd\nexit\n")
  session.wait(on_data=lambda chunk: chunks.append(chunk.decode("utf-8")), timeout=5)
  print("".join(chunks))
  ```

  ```typescript TypeScript SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  const session = await machine.pty.open({ cols: 100, rows: 30, cwd: "/workspace" });
  session.send("pwd\nexit\n");
  for await (const chunk of session.output()) {
    process.stdout.write(chunk);
  }
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace machine pty create mch_123 --cols 120 --rows 30
  ```

  ```bash HTTP API theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  # PTY sessions are created over the machine WebSocket channel.
  # Connect to /v1/machines/mch_123/ws and send a pty start message.
  # See ../reference/websocket-protocol for message shapes.
  ```
</CodeGroup>

## Disconnect and reconnect

Reconnecting to an existing session by `session_id` is available from the Python
SDK and CLI, and over the machine WebSocket for raw clients. The TypeScript SDK
opens a new session per `pty.open()` call and does not reconnect to an existing
session.

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  session_id = session.session_id
  session.disconnect()

  reattached = machine.pty.connect(
      session_id=session_id,
      on_data=lambda chunk: print(chunk.decode("utf-8"), end=""),
  )
  reattached.send_input("echo reattached\n")
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace machine pty connect mch_123 --session-id ses_123
  ```

  ```bash HTTP API theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  # Reconnect over the machine WebSocket channel using the session_id.
  # Connect to /v1/machines/mch_123/ws and send a pty connect message.
  # See ../reference/websocket-protocol for message shapes.
  ```
</CodeGroup>

Use the `session_id` printed by `machine pty create` with `--session-id`.
Numeric `pid` reconnect remains available for legacy scripts. In a local TTY,
`connect` forwards keyboard input, streams PTY output, and tracks terminal
resize events. With `--json`, it waits for completion, forwards piped stdin
when present, and prints the final result. PTY session IDs and legacy PIDs are
not durable across hibernate/resume.

## Manage sessions

Listing, resizing, and killing sessions are available across all clients and use
the `session_id` returned by create.

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  sessions = machine.pty.list_sessions()
  session_id = sessions[0].session_id
  machine.pty.resize_session(session_id, 140, 40)
  machine.pty.kill_session(session_id)
  ```

  ```typescript TypeScript SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  const sessions = await machine.pty.listSessions();
  const sessionId = sessions[0].sessionId;
  await machine.pty.resizeSession(sessionId, 140, 40);
  await machine.pty.killSession(sessionId);
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace machine pty list mch_123
  nullspace machine pty resize mch_123 ses_123 --cols 140 --rows 40
  nullspace machine pty kill mch_123 ses_123
  ```

  ```bash HTTP API theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  curl "${NULLSPACE_API_URL}/v1/machines/mch_123/pty" \
    -H "Authorization: Bearer ${NULLSPACE_API_KEY}"

  curl -X POST "${NULLSPACE_API_URL}/v1/machines/mch_123/pty/ses_123/resize" \
    -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{ "cols": 140, "rows": 40 }'

  curl -X DELETE "${NULLSPACE_API_URL}/v1/machines/mch_123/pty/ses_123" \
    -H "Authorization: Bearer ${NULLSPACE_API_KEY}"
  ```
</CodeGroup>

The session handle exposes `id`, `session_id`, `pid`, `is_connected`,
`exit_code`, and `error`. It also supports byte iteration when you want to read
PTY output directly:

```python theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
for chunk in session:
    print(chunk.decode("utf-8"), end="")
```

Use `session.resize(cols, rows)` for the active WebSocket handle. Use
`resize_session(session_id, cols, rows)` when you are managing a session by ID.

## Related

* [Commands](../commands/overview)
* [WebSocket protocol](../reference/websocket-protocol)
* [Desktop automation](../desktop/automation)
