Runtime

How to run a background process in a sandbox

Call spawn() with the command; it starts a server, watcher or REPL, returns at once, and keeps running after you disconnect.

On Runtime a background process outlives the connection that started it, and a paused sandbox keeps it running across the pause. Reconnect from another process and get it back by id, with its output from the start. A sandbox whose server sits waiting costs $0.03125 an hour at 2 vCPU and 4 GiB, and $0.08 an hour with both CPUs busy (pricing, checked 25 September 2026).

Start a server and a REPL

TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create();const server = await sbx.spawn("python3 -m http.server 8000", { cwd: "/workspace" });console.log(server.id, server.info.state);const repl = await sbx.spawn(["python3", "-i", "-q"], { stdin: "pipe" });await repl.write("print(21 * 2)\n");await repl.write("exit()\n", { eof: true });console.log((await repl.wait()).stdout);for (const p of await sbx.processes.list()) console.log(p.id, p.state, p.command);await server.kill("SIGTERM");
Pythonfrom withruntime import Sandboxwith Sandbox.create() as sbx:    server = sbx.spawn("python3 -m http.server 8000", cwd="/workspace")    print(server.id, server.info["state"])    repl = sbx.spawn(["python3", "-i", "-q"], stdin="pipe")    repl.write("print(21 * 2)\n")    repl.write("exit()\n", eof=True)    print(repl.wait().stdout)    for process in sbx.processes():        print(process["id"], process["state"], process["command"])    server.kill("SIGTERM")

A string runs under bash -c; a list runs the program with no shell. stdin: "pipe" keeps the process's input open so write() can feed it, and eof closes it.

From the command line

spawn prints the process id, ps lists processes, and logs prints what one has written so far and returns, even while it runs:

Terminalid=$(runtime sandbox create)pid=$(runtime sandbox spawn "${id}" -- python3 -m http.server 8000)runtime sandbox ps "${id}"runtime sandbox logs "${id}" "${pid}"runtime sandbox kill "${id}" "${pid}"runtime sandbox stop "${id}"
Terminalruntime sandbox logs "${id}" "${pid}" -f   # follow until the process exits

An agent over MCP calls runtime_sandbox_exec with "background": true, then runtime_sandbox_process with "action": "read" to follow its output (MCP).

Get a process back later

A process does not belong to the script that started it. Save its id, and any later process reconnects and reads from wherever it left off:

TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.connect(process.env.SANDBOX_ID!);const job = await sbx.processes.get(process.env.PROCESS_ID!);for await (const event of job.output({ cursor: 0 })) {  if (event.type === "stdout") process.stdout.write(event.data);  if (event.type === "exit") console.log("exit", event.exitCode);}
Pythonimport osfrom withruntime import Sandboxsbx = Sandbox.connect(os.environ["SANDBOX_ID"])job = sbx.process(os.environ["PROCESS_ID"])for event in job.output(cursor=0):    if event["type"] == "stdout":        print(event["data"], end="")

output() yields every event from the start, or from a cursor, until the process exits.

What a process gets

Setting or limit Value
Returns At once, with the process id and its state
Input stdin: "pipe" (Python stdin="pipe") for write(); eof closes it
Signals kill("SIGTERM") or any signal name; POST …/processes/{id}:signal
Output kept The latest 1 MiB of each process's output, in the sandbox
Across a pause Running processes are kept with memory and carry on after the wake
Lifetime Until it exits, is killed, or the sandbox stops
Terminal Add pty: { cols, rows } for a program that needs one
Cost No charge per process; the sandbox's measured CPU and reserved memory

Mistakes to avoid

  • Starting a server with exec. A process started by exec ends with its command, and exec waits for it. A server, a file watcher or a queue worker goes in spawn.
  • Printing more than 1 MiB and reading it later. A reader that was away while more than that came out gets a truncated event saying how many bytes are gone, and wait() sets both truncation flags. Send a chatty process's output to a file and read the file.
  • Forgetting the lease. A sandbox runs until its lease ends, then pauses by default, and its processes pause with it. For a server that must answer all day, see keep a sandbox running.
  • Opening a port with nothing listening. Check processes.list() shows the server as running before you share its port with a preview or runtime sandbox port-forward.

Facts on this page were checked on 25 September 2026.