Skip to content

Process & Code Execution

exec runs a command, buffers its full output, and returns when the command exits. Use it for short, non-interactive commands.

execStream opens a live WebSocket connection that streams stdout/stderr in real time, accepts stdin, and optionally allocates a pseudo-terminal (PTY) for interactive programs like bash, vim, or top.

Use caseMethod
ls, git status, anything short and non-interactiveexec
npm install, make, anything where you want live outputexecStream
bash, python -i, vim, anything interactiveexecStream with tty: true
Multi-gigabyte outputexecStream
const result = await sandbox.exec({ command: 'echo hello' })
console.log(result.stdout) // "hello\n"
console.log(result.exitCode)
// With working directory and environment variables
const result2 = await sandbox.exec({
command: 'node index.js',
workDir: '/workspace',
env: { NODE_ENV: 'production' },
timeoutSeconds: 30,
})
const handle = sandbox.execStream({
command: 'npm install',
workdir: '/workspace',
onStdout: chunk => process.stdout.write(chunk),
onStderr: chunk => process.stderr.write(chunk),
})
const { code } = await handle.done
console.log(`exited with ${code}`)

In PTY mode, stdout and stderr are merged onto the terminal, so only onStdout fires.

const handle = sandbox.execStream({
command: 'bash',
tty: true,
cols: process.stdout.columns,
rows: process.stdout.rows,
onStdout: chunk => process.stdout.write(chunk),
})
process.stdin.setRawMode?.(true)
process.stdin.on('data', chunk => handle.write(chunk))
process.stdout.on('resize', () => {
handle.resize(process.stdout.columns, process.stdout.rows)
})
await handle.done
handle.signal('INT') // Ctrl-C
handle.signal('TERM')
handle.signal('KILL')

Signals target the process group, so child processes receive them too.

For persistent interactive processes that survive reconnects, see Sessions.