Skip to main content
A PTY (pseudo-terminal) attaches a real TTY to a process inside the sandbox. Unlike commands.run, which returns a single {stdout, stderr, exit_code} blob when the process finishes, a PTY lets you:
  • Stream bytes as they’re produced — the right choice for anything that paints the screen (progress bars, TUI apps, live logs).
  • Send keystrokes mid-execution — required for password prompts, OAuth pasteback, confirmation dialogs, REPLs, and editors.
  • Resize on the fly — if the user drags a terminal pane, the remote program sees a SIGWINCH and redraws.
  • Reconnect and fan out — multiple clients can subscribe to the same PTY concurrently, and clients can disconnect without killing the shell.
Inside the sandbox the PTY runs an interactive bash -l (login shell) with TERM=xterm-256color pre-set, so ANSI colour codes, cursor escapes, tput queries, and ncurses-based TUIs (vim, htop, less, nano) all render correctly.

When to use PTY vs commands.run

Default to commands.run. Reach for pty.create only when the command requires a terminal.

Architecture

pty.create takes four REST calls plus one SSE stream: The SSE stream stays open for the life of the session. Output bytes are emitted as event: data frames with base64-encoded payload, and a final event: exit frame announces the remote exit code.

Session lifecycle

A PTY session is bounded by two independent timeouts — whichever fires first ends the session:
  • The sandbox timeout (set at Sandbox.create(timeout=...), default 300s) kills the whole sandbox and every PTY inside it.
  • The PTY timeout (set at sandbox.pty.create(timeout=...), default 3600s) kills just that one PTY. Pass 0 for no PTY-level TTL — sessions then live until the sandbox itself expires.
For an interactive coding-agent session you typically raise both:

Quick start

Callback-style — your function receives every chunk of PTY output as it arrives. Good for forwarding to an xterm.js instance or your local terminal.

Next steps