# How to open an interactive terminal in a sandbox Run `runtime sandboxes shell ` from your terminal. Or call `sbx.terminal()` in code to open a real terminal over a WebSocket. **On Runtime, the terminal is a real one, with colors, prompts and resizing. The sandbox opens no port to provide it.** The terminal travels over one authenticated WebSocket through Runtime's API. So only a key that may run commands in that sandbox can connect. ## From your own terminal ```bash no-run runtime sandboxes shell "${id}" # an interactive terminal, like ssh runtime sandboxes ssh "${id}" # the same through OpenSSH, as the sandbox user runtime sandboxes ssh "${id}" -- make test # one command; exits with its code ``` `${id}` can be the sandbox's id or its name. On first use, `ssh` makes an SSH key for this machine. It sends only the public half. Run `runtime sandboxes ssh config --install` once. After that, every sandbox answers as the host `.runtime` for ssh, scp, VS Code and JetBrains Gateway ([SSH and editors](/docs/editors)). ## From code What you write is typed into the terminal. What it prints comes back as bytes, escape codes included: ```ts import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create(); const term = await sbx.terminal({ cols: 120, rows: 40, onData: (bytes) => process.stdout.write(bytes), }); term.write("echo hello from the terminal\n"); term.resize(100, 30); term.write("exit\n"); console.log("exit code", await term.exited); ``` ```python from withruntime import Sandbox with Sandbox.create() as sbx: term = sbx.terminal(cols=120, rows=40) term.write("echo hello from the terminal\n") term.write("exit\n") while (chunk := term.recv()) is not None: print(chunk.decode(errors="replace"), end="") ``` In TypeScript, `term.exited` resolves with the shell's exit code. In Python, `recv()` returns `None` once the terminal has closed. ## The protocol, if you speak it yourself `GET /v1/sandboxes/{id}/terminal` with `Upgrade: websocket` and the bearer header opens one ([terminals](/docs/api#terminals)). | Part | What it is | | -------------------- | ------------------------------------------------------------------------------------------ | | Query | `cols`, `rows`, `command` (default `bash -l`), `cwd`, or `processId` | | Binary frames | Terminal bytes, both ways | | Text frames you send | `{"type":"resize","cols":120,"rows":40}` | | Text frames it sends | `{"type":"ready","processId":...}`, then `{"type":"exit","exitCode":...}` | | Attach to a process | Start it with `spawn(..., { pty: { cols, rows } })`, then pass its `processId` | | Limits | 64 terminals open per organization and 2 per sandbox, up to 340; 12 in one sandbox at most | | Who you are | The `runtime` user, whose home is `/workspace`, with `sudo` | | Cost | Nothing for the terminal. The sandbox's measured CPU and reserved memory | ## Terminal, exec or SSH? | You want | Use | | ---------------------------------------- | -------------------------------------------------------- | | One command and its result | `exec`, which waits and returns the exit code and output | | A program that asks questions or redraws | `terminal()` or `runtime sandboxes shell` | | Your editor, scp or rsync | `runtime sandboxes ssh` and `ssh .runtime` | | A port on your laptop | `runtime sandboxes port-forward ` | ## Mistakes to avoid - **Sending a command without a newline.** The terminal runs what you type only when it sees `\n`, the same as a keyboard's Enter. - **Parsing terminal output as plain text.** It carries color and cursor codes. For output you plan to parse, run the command with `exec`. It returns clean `stdout` and `stderr`. - **Leaving terminals open.** An organization can have 64 terminals open at the same time, and 12 in any one sandbox. Write `exit`, or close the socket, when a session ends. Past the limit, you get 429 with `Retry-After`. - **Setting a time limit for a long session.** An open terminal keeps a sandbox running. A sandbox has no time limit by default. One created with `timeoutSeconds` still ends at that limit. Leave it out, or see [extend a sandbox's time limit](/how-to/extend-a-sandbox-lease). ## Related - [Run a background process](/how-to/run-a-background-process) and attach a terminal to it. - [Per-user dev environments](/use-cases/per-user-dev-environments), where each user gets a shell of their own. - [Coding agent sandbox](/use-cases/coding-agent-sandbox) for agents that need a shell. - [An interactive terminal](/docs/javascript#an-interactive-terminal) in the SDK reference. Facts on this page were checked on 26 October 2026.