Skip to main content
Sandboxes have PTY session support for interactive terminal sessions. SDK is available for Node.js and Python to build your own terminal client. This page documents how to build a terminal client, to start a terminal session, see CLI Terminal.

Create and Attach to a Terminal

Create a terminal and attach to its websocket stream:
const terminal = await sandbox.terminal.create({
  command: "bash",
  args: ["-l"],
  rows: 24,
  cols: 80,
});

const connection = await terminal.attach();

for await (const event of connection.events()) {
  if (event.type === "output") {
    process.stdout.write(event.data);
    continue;
  }

  console.log("Exit code:", event.status.exitCode);
  break;
}

Write Input and Resize the PTY

Send input through the attached connection and resize the terminal:
const terminal = await sandbox.terminal.create({
  command: "bash",
  args: ["-l"],
});

const connection = await terminal.attach();

await connection.resize(32, 110);
await connection.write("pwd\n");
await connection.write("echo terminal-ok\n");
await connection.write("exit\n");

await connection.close();

Get, Refresh, and Wait

Fetch an existing terminal or wait for it to complete:
const terminal = await sandbox.terminal.create({
  command: "bash",
  args: ["-lc", "echo hello-from-terminal"],
});

const fetched = await sandbox.terminal.get(terminal.id, true);
console.log(fetched.current.output?.map((chunk) => chunk.data).join(""));

const status = await terminal.wait({
  timeoutMs: 2_000,
  includeOutput: true,
});

console.log(status.running, status.exitCode);

Signal and Kill

You can signal or kill a terminal-backed process:
const terminal = await sandbox.terminal.create({
  command: "bash",
  args: ["-lc", "sleep 30"],
});

await terminal.signal("TERM");
const status = await terminal.wait({ timeoutMs: 5_000 });
console.log("Still running:", status.running);
console.log("Exit code:", status.exitCode);
status.running tells you whether the terminal session is still alive after the signal. After signal("TERM") and a successful wait(...), you would usually expect status.running to be false.

Common Terminal Parameters

command
string
required
Command to launch inside the terminal session.
args
string[]
Optional command arguments.
cwd
string
Working directory for the terminal process.
env
object
Environment variables to set for the terminal process.
rows
number
Initial terminal row count.
cols
number
Initial terminal column count.
timeoutMs
number
Optional PTY runtime limit in milliseconds.
sandbox.pty is an alias for sandbox.terminal.

Create Interactive Terminal

Run an interactive sandbox shell from your backend process and bridge local terminal input/output to the sandbox PTY stream.
const terminal = await sandbox.terminal.create({
  command: "bash",
  args: ["-l"],
  rows: process.stdout.rows ?? 24,
  cols: process.stdout.columns ?? 80,
});

console.log("Sandbox PTY ID:", terminal.id);

const connection = await terminal.attach();

const onStdinData = (chunk: Buffer) => {
  void connection.write(chunk);
};

const onResize = () => {
  void connection.resize(process.stdout.rows ?? 24, process.stdout.columns ?? 80);
};

if (process.stdin.isTTY) {
  process.stdin.setRawMode(true);
}
process.stdin.resume();
process.stdin.on("data", onStdinData);

if (process.stdout.isTTY) {
  process.stdout.on("resize", onResize);
}

try {
  for await (const event of connection.events()) {
    if (event.type === "output") {
      process.stdout.write(event.data);
      continue;
    }

    process.stdout.write(`\n[remote exited: ${event.status.exitCode ?? "unknown"}]\n`);
    break;
  }
} finally {
  process.stdin.off("data", onStdinData);
  process.stdin.pause();
  process.stdout.off("resize", onResize);
  if (process.stdin.isTTY) {
    process.stdin.setRawMode(false);
  }
  await connection.close();
  await sandbox.stop();
}
The Python raw-mode bridge uses termios and tty, so it is intended for POSIX terminals (Linux/macOS).