Skip to main content
A sandbox is what you start when you want your agent to work against Pome: one id, one lifetime, and one to three digital twins your agent talks to. It is also the unit your plan counts, so “how many can I have open at once” is a question about sandboxes, never about twins. Every other page in these docs uses the word. This one defines it.

What one sandbox holds

The twins inside a sandbox are not independent of it. They share its id, its bearer token, its lifetime and its line on the bill. What they do not share is state. Each keeps its own world and writes its own tape, so a write through GitHub is not visible to Slack. Your agent is what carries a fact from one twin to the other; the platform moves nothing between them. That is what makes a cross-twin task worth setting rather than a limitation of one. The Cross-twin consistency example can assert that a GitHub decision reached Slack precisely because nothing propagates it — its committed defect is an agent that decides correctly in GitHub and never tells Slack, and an exam whose platform carried the fact across could never catch that. Two twins, one sandbox walks it end to end with both tapes on screen. State never crosses between sandboxes. Each one boots its twins from a declared starting state, so two sandboxes on the same seed find the same world. A sandbox is also all-or-nothing. If one of its twins cannot come up, the whole sandbox fails to start rather than starting partly — you never get a half-built world your agent then works in.

How long a sandbox lives

Two clocks run, and whichever expires first ends the sandbox: Past either one the sandbox is closed and every call against it answers 410 session_expired. Nothing about it is recoverable; start a new one.
Finalize while the sandbox is still live. Pome writes the run row at finalize, and finalize reads the tape off the twins — which are gone once the sandbox closes. A sandbox you let expire leaves nothing to score, and no run you can go back for.
Stopping a sandbox yourself has the same consequence and says so out loud: DELETE /v1/sandboxes/:id and pome sandbox stop both refuse an ungraded sandbox unless you confirm you meant to discard its run.

The two limits that are both three

One number causes more confusion here than the rest of the platform put together, because two unrelated limits can both read three. They measure different things — one is depth, the other is width — and they move independently. If your plan’s concurrency allowance also happens to be three, that is two numbers colliding, not one rule: raising your plan raises the second and never the first, and no plan has ever raised the first. Read your own concurrency number rather than assuming it. GET /v1/usage reports sessions_used against sessions_quota, and sessions_used counts sandboxes open right now — not sandboxes started this month — so it falls again the moment you finalize or stop one. Dashboard → Usage reads the same counter.
Because concurrency is a ceiling rather than a monthly budget, a 402 from sandbox create is not a wall you wait out. Finalize an open sandbox and the slot frees immediately. See Billing semantics for which 402 is which.

One twin, or three?

Both are true, of different doors. The platform allows three; the dashboard’s own selector currently offers one. So the dashboard’s limit is a limit of that screen, not of the platform. To start a multi-twin sandbox today, use the CLI, the REST API, or a task that declares more than one twin.

What a sandbox gives you that a local twin does not

pome twin start <twin> runs a digital twin on your own machine with no account and no sandbox. You get the twin, and you get its recorded tape from GET /_pome/events — enough to drive an agent and to score it however you like. The Get started path is built entirely on it. What it does not give you is a score. There is no local scoring: the CLI captures and the cloud grades. Everything below needs a sandbox, and there is no offline equivalent of any of it —
  • a verdict against a task’s [code] criteria, with the evidence pointer behind it;
  • a run that persists — its trace, its tape, its state diffs — instead of a tape that dies with the process;
  • trials: n independent attempts at one task, which is how reliability gets measured rather than asserted;
  • the narrator’s summary and handoff;
  • anything on the dashboard.
pome run --local sits on the same line: it captures a trace and grades nothing. pome eval <run-dir> is what sends that trace up for a verdict. The choice is not “hosted or local for the same result”. It is:
  • A twin and a tape you score yourself → a local twin. No account.
  • Pome’s verdict on your agent → a sandbox.

Starting one

A run started by pome run creates and tears down its own sandbox; you do not manage one by hand for an ordinary run.

What a sandbox costs

Starting a sandbox costs no agent eval. Provisioning twins, launching your agent, watching it work and reading its tape are all free — the eval is charged when the run is graded at finalize, and at no other moment. What a sandbox does consume while it is open is a concurrency slot, which is the plan limit above. Billing semantics has the full rule: what counts as a scored run, when you are not charged, and which 402 means which. For what a plan costs and what each one includes, see pome.sh pricing — the prices live there, and only there, so there is nothing here to drift out of date.

Next

Billing semantics

What consumes a meter, what is free, and the three 402s worth telling apart.

Dashboard

Where the sandboxes you start, and the runs they produce, show up.

pome sandbox

Create, list, and stop sandboxes from a terminal.

REST API

The control plane that starts them, and the shape every error takes.