Skip to main content
The PTY (pseudo-terminal) module allows you to create interactive terminal sessions in the sandbox with real-time, bidirectional communication. Unlike commands.run() which executes a command and returns output after completion, PTY provides:
  • Real-time streaming - Output is streamed as it happens via callbacks
  • Bidirectional input - Send input while the terminal is running
  • Interactive shell - Full terminal support with ANSI colors and escape sequences
  • Session persistence - Disconnect and reconnect to running sessions

Create a PTY session

Use sandbox.pty.create() to start an interactive bash shell.
import { Sandbox } from '@e2b/code-interpreter'

const sandbox = await Sandbox.create()

const terminal = await sandbox.pty.create({
  cols: 80,              // Terminal width in characters
  rows: 24,              // Terminal height in characters
  onData: (data) => {
    // Called whenever terminal outputs data
    process.stdout.write(data)
  },
  envs: { MY_VAR: 'hello' },  // Optional environment variables
  cwd: '/home/user',          // Optional working directory
  user: 'root',               // Optional user to run as
})

// terminal.pid contains the process ID
console.log('Terminal PID:', terminal.pid)
The PTY runs an interactive bash shell with TERM=xterm-256color, which supports ANSI colors and escape sequences.

Timeout

By default, PTY sessions have a 60-second timeout which limits the total duration of the session. When the timeout is reached, the connection to the PTY session will be closed regardless of activity. For long-running sessions, set timeoutMs: 0 (JavaScript) or timeout=0 (Python) to disable the timeout.
import { Sandbox } from '@e2b/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,  // No timeout for long-running sessions
})

Send input to PTY

Use sendInput() in JavaScript or send_stdin() in Python to send data to the terminal. These methods return a Promise (JavaScript) or complete synchronously (Python) - the actual output will be delivered to your onData callback.
import { Sandbox } from '@e2b/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')
)

Resize the terminal

When the user’s terminal window changes size, notify the PTY with resize(). The cols and rows parameters are measured in characters, not pixels.
import { Sandbox } from '@e2b/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,
})

Disconnect and reconnect

You can disconnect from a PTY session while keeping it running, then reconnect later with a new data handler. This is useful for:
  • Resuming terminal sessions after network interruptions
  • Sharing terminal access between multiple clients
  • Implementing terminal session persistence
import { Sandbox } from '@e2b/code-interpreter'

const sandbox = await Sandbox.create()

// Create a PTY session
const 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 command
await sandbox.pty.sendInput(pid, new TextEncoder().encode('echo hello\n'))

// Disconnect - PTY keeps running in the background
await terminal.disconnect()

// Later: reconnect with a new data handler
const reconnected = await sandbox.pty.connect(pid, {
  onData: (data) => console.log('Handler 2:', new TextDecoder().decode(data)),
})

// Continue using the session
await sandbox.pty.sendInput(pid, new TextEncoder().encode('echo world\n'))

// Wait for the terminal to exit
await reconnected.wait()

Kill the PTY

Terminate the PTY session with kill().
import { Sandbox } from '@e2b/code-interpreter'

const sandbox = await Sandbox.create()

const terminal = await sandbox.pty.create({
  cols: 80,
  rows: 24,
  onData: (data) => process.stdout.write(data),
})

// Kill the PTY
const killed = await sandbox.pty.kill(terminal.pid)
console.log('Killed:', killed)  // true if successful

// Or use the handle method
// await terminal.kill()

Wait for PTY to exit

Use wait() to wait for the terminal session to end (e.g., when the user types exit).
import { Sandbox } from '@e2b/code-interpreter'

const sandbox = await Sandbox.create()

const terminal = await sandbox.pty.create({
  cols: 80,
  rows: 24,
  onData: (data) => process.stdout.write(data),
})

// Send exit command
await sandbox.pty.sendInput(terminal.pid, new TextEncoder().encode('exit\n'))

// Wait for the terminal to exit
const result = await terminal.wait()
console.log('Exit code:', result.exitCode)

Interactive terminal (SSH-like)

Building a fully interactive terminal (like SSH) requires handling raw mode, stdin forwarding, and terminal resize events. For a production implementation, see the E2B CLI source code which uses the same sandbox.pty API documented above.