The PTY, or pseudo-terminal, module enables interactive terminal sessions inside the sandbox with real-time, bidirectional communication.A PTY session supports real-time streaming, delivering terminal output continuously through callbacks as it is produced, and provides bidirectional input, allowing data to be sent while the session is still running. It also offers an interactive shell experience with full terminal behavior, including ANSI colors and escape sequences, and supports session persistence, so a running session can be detached and reconnected later.
The timeout setting is configurable and determines how long the PTY session remains active. You can keep a PTY session open indefinitely by setting timeoutMs: 0 in JavaScript or timeout=0 in Python. The session uses a 60-second timeout by default.
import { Sandbox } from 'novita-sandbox/code-interpreter'const sandbox = await Sandbox.create()const terminal = await sandbox.pty.create({ cols: 80, rows: 24, onData: (data) => process.stdout.write(data), timeoutMs: 0, // Keep the session open indefinitely})
You can use sendInput() in JavaScript or send_stdin() in Python to send data to the terminal.In JavaScript, sendInput() returns a Promise, and any terminal output is delivered through the onData callback rather than returned directly.
In Python, send_stdin() completes synchronously, and any terminal output is delivered through the on_pty callback passed to wait().
import { Sandbox } from 'novita-sandbox/code-interpreter'const sandbox = await Sandbox.create()const terminal = await sandbox.pty.create({ cols: 80, rows: 24, onData: (data) => process.stdout.write(data),})// Send a command (don't forget the newline!)await sandbox.pty.sendInput( terminal.pid, new TextEncoder().encode('echo "Hello from PTY"\n'))
You can use resize() to notify the PTY when the user changes the terminal window size.
The cols and rows values represent the terminal dimensions in characters rather than pixels.
import { Sandbox } from 'novita-sandbox/code-interpreter'const sandbox = await Sandbox.create()const terminal = await sandbox.pty.create({ cols: 80, rows: 24, onData: (data) => process.stdout.write(data),})// Resize to new dimensions (in characters)await sandbox.pty.resize(terminal.pid, { cols: 120, rows: 40,})
A PTY session can remain active even after the client disconnects. You can detach from the session and reconnect to it again later with a new data handler.This can be used to recover from network interruptions, support terminal access from multiple clients, and preserve session state across reconnects.
import { Sandbox } from 'novita-sandbox/code-interpreter'const sandbox = await Sandbox.create()// Create a PTY sessionconst terminal = await sandbox.pty.create({ cols: 80, rows: 24, onData: (data) => console.log('Handler 1:', new TextDecoder().decode(data)),})const pid = terminal.pid// Send a commandawait sandbox.pty.sendInput(pid, new TextEncoder().encode('echo hello\n'))// Disconnect - PTY keeps running in the backgroundawait terminal.disconnect()// Later: reconnect with a new data handlerconst reconnected = await sandbox.pty.connect(pid, { onData: (data) => console.log('Handler 2:', new TextDecoder().decode(data)),})// Continue using the sessionawait sandbox.pty.sendInput(pid, new TextEncoder().encode('echo world\n'))// Wait for the terminal to exitawait reconnected.wait()
You can use the same sandbox.pty API described above to create a fully interactive terminal such as SSH by handling raw mode, stdin forwarding, and terminal resize events.