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=searchFilters 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.datais one page. Loop withfor await(orforin Python), or calltoArray(), to reach every match. - Expecting stopped sandboxes in the list. They are left out by default.
Pass
includeStopped: trueto 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
envor 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.
Related
- Find a sandbox by name for one handle per sandbox.
- Agent evals and SWE-bench, where each run labels its sandboxes.
- Keep a sandbox running for sandboxes you do not want cleaned up.
- Find sandboxes again in the SDK reference.
Facts on this page were checked on 25 September 2026.