# How to keep an AI agent running for hours in a cloud sandbox Run the agent in a sandbox whose lease renews itself, start it with spawn, and reattach to its output from any process later. **On Runtime an eight-hour agent run costs about 26 cents** on a 2 vCPU, 4 GiB sandbox that spends most of its time waiting on its model, because Runtime bills the CPU the agent's commands use, not the CPUs it holds. At the rates in force on 25 September 2026 that sandbox costs $0.03125 an hour while it waits and $0.08 an hour with both CPUs busy. If the lease ever does run out, the default is to pause, so the agent's memory and processes are kept rather than lost. ## The short answer Create a paid sandbox with `persistent: true` and a spending cap, copy the agent in, and start it as a background process. Save the two ids; they are all you need to come back: ```ts check import { Sandbox } from "withruntime"; const sbx = await Sandbox.create({ name: "agent-run-981", funding: "paid", persistent: true, // the lease renews itself on the server while credit lasts maxTotalCostMicros: 5_000_000, // never more than $5 over its life diskMiB: 8192, labels: { kind: "long-agent", run: "981" }, }); await sbx.files.upload("./agent", "/workspace/agent"); const agent = await sbx.spawn("python3 main.py --task 'Port the test suite to Vitest'", { cwd: "/workspace/agent", }); console.log(sbx.id, agent.id); // keep these in your database ``` ```python check from withruntime import Sandbox sbx = Sandbox.create( name="agent-run-981", funding="paid", persistent=True, # the lease renews itself on the server while credit lasts max_total_cost_micros=5_000_000, # never more than $5 over its life disk_mib=8192, labels={"kind": "long-agent", "run": "981"}, ) sbx.files.upload("./agent", "/workspace/agent") agent = sbx.spawn("python3 main.py --task 'Port the test suite to Vitest'", cwd="/workspace/agent") print(sbx.id, agent.id) # keep these in your database ``` A process started with `spawn` belongs to the sandbox, not to your connection. Your server can restart, deploy or crash, and the agent keeps working. ## Come back to it later Any process that has the ids can reattach, read progress and follow the output from the first byte: ```ts check import { Sandbox } from "withruntime"; const sbx = await Sandbox.connect(process.env.SANDBOX_ID!); const agent = await sbx.processes.get(process.env.PROCESS_ID!); console.log(agent.info.state); for await (const event of agent.output({ cursor: 0 })) { if (event.type === "stdout") process.stdout.write(event.data); if (event.type === "exit") console.log("agent finished with", event.exitCode); } ``` ```python check import os from withruntime import Sandbox sbx = Sandbox.connect(os.environ["SANDBOX_ID"]) agent = sbx.process(os.environ["PROCESS_ID"]) print(agent.info["state"]) for event in agent.output(cursor=0): if event["type"] == "stdout": print(event["data"], end="") elif event["type"] == "exit": print("agent finished with", event["exitCode"]) ``` The sandbox keeps the latest 1 MiB of each process's output. An agent that talks for hours should also append its steps to a file, such as `/workspace/progress.jsonl`, which `files.readText` reads at any time. ## Four ways past the one-hour lease A sandbox's lease, `timeoutSeconds`, is at most 3,600 seconds ahead. Pick how it gets renewed: | Way | Who renews it | Suits | | ------------------------------- | ----------------------------------------- | --------------------------------------------- | | `persistent: true` (paid) | The server, while the account has credit | An agent that must outlive your own process | | `keepAlive()` | Your process, once a minute | A job runner that owns the sandbox until done | | `extend(seconds)` | You, when you choose | An agent loop that checks in at each step | | `onLeaseEnd: "pause"` (default) | Nobody: it pauses, and a request wakes it | Work that may stop and resume without loss | A single `exec` can run for up to 24 hours, and a timeout comes back as a result with the output so far, not an exception. On the free trial each session lasts up to an hour and can be extended within the 50 hours an account starts with; `persistent` needs paid credit. ## Pause while it waits for a person Long agents often stop to ask for approval. Pause the sandbox at that point. Compute billing ends once its processors stop, and the agent is exactly where it was when the answer comes: ```ts check import { Sandbox } from "withruntime"; const sbx = await Sandbox.connect(process.env.SANDBOX_ID!); await sbx.pause(); // files, memory and the agent process are kept // ... hours later, when the reviewer answers: await sbx.wake(); await sbx.files.write("/workspace/agent/approval.txt", "approved"); ``` A paid pause is kept 30 days by default and up to 365. While paused it pays only for the disk and memory blocks it alone owns, at $0.08 per GB per 30-day month. ## Know when it ends Ask for a webhook when a sandbox stops, so a crashed or finished agent never goes unnoticed, and read its CPU and memory while it runs: ```ts check import { Runtime, Sandbox } from "withruntime"; const runtime = new Runtime(); await runtime.webhooks.create({ url: "https://example.com/hooks/runtime", events: ["sandbox.stopped", "sandbox.start_failed"], }); const sbx = await Sandbox.connect(process.env.SANDBOX_ID!); const { latest } = await sbx.metrics({ range: "1h" }); console.log(latest?.cpuPercent); ``` `stopReason` on the `sandbox.stopped` event says why it stopped ([metrics and webhooks](/docs/observability)). ## What an hours-long agent needs | Need | How Runtime covers it | | ---------------------------- | ------------------------------------------------------------------------------- | | Run past any one connection | `spawn` processes live in the sandbox; `processes.get(id)` finds them again | | Run past the lease | `persistent`, `keepAlive` or `extend`; the lease ends in a pause by default | | A bounded bill | `maxTotalCostMicros` per sandbox and a daily spending limit per key | | Cheap waiting | Billed on measured CPU, with a floor of a twentieth of a vCPU | | Waiting days for a human | Pause keeps memory and processes for 1 to 365 days | | No output lost on reconnect | `output({ cursor })` replays from any byte of the kept 1 MiB | | A full machine for the agent | Ubuntu 24.04, `sudo`, Python 3.12, Node.js 24, Docker with `sudo enable-docker` | ## What it costs Take one run of 8 hours on 2 vCPU and 4 GiB, where the agent's commands use on average 0.1 of a vCPU because most of the time goes on model calls: ``` CPU: 8 h × 0.1 vCPU × $0.025 = $0.02 Memory: 8 h × 4 GiB × $0.0075 = $0.24 Total: $0.26 ``` A hundred such runs a month cost about $26. Runtime charges $0.025 per vCPU-hour of measured CPU and $0.0075 per GiB-hour of memory while running, with no plan fee ([pricing](/docs/pricing)). ## Start ```bash no-run npx withruntime sandbox run --trial --keep -- python3 --version ``` Approve the link it prints in your browser, then follow the process of a running agent from a terminal with `runtime sandbox logs -f` ([CLI](/docs/cli#sandboxes)). Related: [background agents](/use-cases/background-agents), [agent memory that persists](/use-cases/agent-memory-persistence), [pause and resume a sandbox](/how-to/pause-and-resume-a-sandbox), [coding agent sandbox](/use-cases/coding-agent-sandbox). Facts on this page were checked on 25 September 2026.