Runtime

How to label and list sandboxes

Pass labels: { team: "search" } when you create a sandbox, then runtime.sandboxes.list({ labels }) returns every sandbox that matches.

On Runtime every list, in every product, returns the same page object, and one loop walks every page. A sandbox takes up to 32 key: value labels, so a CI run, a customer or an agent task can find and clean up exactly its own sandboxes. A paid account holds 100 sandboxes at once to start, running or paused (pricing, checked 25 September 2026).

Label at create, filter when you list

TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();const sbx = await runtime.sandboxes.create({  labels: { team: "search", job: "42", ci: "true" },});const page = await runtime.sandboxes.list({ labels: { team: "search" }, state: ["running"] });for await (const found of page) console.log(found.id, found.info.name, found.state);await sbx.stop();
Pythonfrom withruntime import Runtimeruntime = Runtime()sbx = runtime.sandboxes.create(labels={"team": "search", "job": "42", "ci": "true"})for found in runtime.sandboxes.list(labels={"team": "search"}, state=["running"]):    print(found.id, found.info["name"], found.state)sbx.stop()
Terminalid=$(runtime sandbox create --name demo --label team=search --label job=42)runtime sandbox lsruntime sandbox get "${id}"runtime sandbox stop "${id}"

--label k=v repeats on runtime sandbox create. runtime ls lists everything the account runs, across every product, not only sandboxes.

Clean up after a CI run

Label each sandbox with the run's id, and stop whatever is left when the run ends, even after a failure:

TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();const run = process.env.GITHUB_RUN_ID ?? "local";await runtime.sandboxes.create({ labels: { ci: run } });for await (const leftover of await runtime.sandboxes.list({ labels: { ci: run } }))  await leftover.stop();
Pythonimport osfrom withruntime import Runtimeruntime = Runtime()run = os.environ.get("GITHUB_RUN_ID", "local")runtime.sandboxes.create(labels={"ci": run})for leftover in runtime.sandboxes.list(labels={"ci": run}):    leftover.stop()

Change labels later

TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.create({ labels: { team: "search" } });await sbx.update({ labels: { team: "search", owner: "ada" } });
Terminalruntime sandbox update "${id}" --name dev-2 --label team=search

Filters and paging

Filter or field What it does
labels Every label given must match; over HTTP, repeat label=key:value
state Such as ["running"] or ["paused"]
name The one live sandbox with that name
includeStopped Stopped sandboxes are left out unless this is true
limit, cursor Page size and the next page, over HTTP
The page page.data, page.hasMore, page.next(), page.toArray(), for await
Python page page.data, page.has_more, page.next_page(), page.to_list(), for
Label limit Up to 32 key: value labels a sandbox
MCP runtime_sandbox_list by state, name or label, or one by id
Cost Listing and labels cost nothing

Mistakes to avoid

  • Reading only the first page. page.data is one page. Loop with for await (or for in Python), or call toArray(), to reach every match.
  • Expecting stopped sandboxes in the list. They are left out by default. Pass includeStopped: true to audit what ran.
  • Putting secrets or personal data in labels. Labels are for finding things, and anyone with a read-only key on the account can list them. Keep secrets in env or in Runtime secrets.
  • Using a label as a unique handle. Many sandboxes can share a label. For exactly one, use a name.
  • Leaving cleanup to luck. A sandbox's lease pauses it when time runs out, and a paused sandbox still counts toward the account's 100. Stop by label at the end of each job.

Facts on this page were checked on 25 September 2026.