Isorun Docs
Sandboxes

Create & Execute

The default runtime loop for agents and jobs, create, execute, destroy.

Create a sandbox, run commands inside it, then destroy it. This is the default runtime loop for agents and short jobs.

Use this pattern for one-shot tasks and short workflows. For anything that needs to outlive a single request, see Lifecycle and hibernation.

Quick example

TypeScript
import { Isorun } from 'isorun'

const isorun = new Isorun()
const sandbox = await isorun.create({ image: 'python:3.12-slim' })

try {
  const result = await sandbox.exec("python3 -c 'print(2**100)'")
  console.log(result.stdout.trim())
  console.log(result.exitCode)
} finally {
  await sandbox.destroy()
}

Choose between exec and execStream

MethodBest forTradeoff
sandbox.exec(cmd, timeoutSec)Short bounded commandsNo incremental output while running
sandbox.execStream(cmd, { onStdout, onStderr })Long builds / tests / trainingSlightly more integration code; resolves to the final result once the command exits
TypeScript
await sandbox.execStream('python3 long_training_loop.py', {
  timeoutSec: 600,
  onStdout: (chunk) => process.stdout.write(chunk),
  onStderr: (chunk) => process.stderr.write(chunk),
})

Handle failures

A non-zero exit code is a normal result, not an exception, check exitCode yourself.

TypeScript
const result = await sandbox.exec('pytest -q', 180)
if (result.exitCode !== 0) {
  console.error(result.stderr)
  throw new Error('tests failed')
}

Clean up and control cost

Always destroy or close sandboxes in finally paths.

  • Prevents leaked runtime costs.
  • Keeps capacity available under load.
  • Makes behavior predictable in production.

A sandbox you forget to destroy keeps billing until its idle timeout fires. Put destroy() in a finally block so it runs even when the command throws.

Next steps

On this page