sandbox_review
Hands a tested version to the person and waits for their report or completion. The card and its product entry appear immediately in their app. The default wait is capped at 25 seconds for clients that have not declared support for longer waits; a configured client can wait up to 30 minutes.
| Input | Output |
|---|---|
id; exactly one of what with open (new card) or reviewId (resume); open is web or box; port (integer 1–65535) with open: "web" only; optional waitSec (integer 0–1800, within the client's supported wait limit; undeclared clients are capped at 25 seconds) |
ok, reviewId, shareUrl (the link to give the person: the review page with the product and the feedback tools), productUrl (the product itself), open (web or box), status, note; after waiting, or when the round already has a report, outcome and, for a report, reportId, fromHuman and images |
Test the flow where the person will use it: tap and type on the box's screen for a phone or desktop app (sandbox_shot shows the result), or go through the web page from a fresh browser session, including its sign-in entry. Leave the product at its starting screen. Create a card with what, written in the person's language. Lead with what they should test, because the card shows only its first two lines: where to start, what to tap or type, and what they see when it works. Then add one short sentence on what you tested yourself. The card holds this text, cut at 400 characters, a product picture and its opening button, which opens what you name in open (below). Call it for every tested version worth their time (Finishing a box).
{ "id": "<boxId>", "what": "Add a task, then go back to the list: the task you added is still there. I added a task and returned to the list in a fresh browser session myself.", "open": "web", "port": 5173 }
The call stays active within the supported wait limit. Use stdio adapter parallelsandbox-mcp 0.4.2 or later for wait negotiation, progress and cancellation forwarding. Progress includes reviewId, shareUrl and productUrl, immediately and then every 15 seconds.
Give the person shareUrl. While the review waits, it opens this review in the ParallelSandbox app without an account or sign-in, with the product and the tools to report on it, and colleagues can use the same link; once the review has ended it is the box's page in the app, which needs the account's sign-in. productUrl is the product itself: the page on port for open: "web", the same review page for open: "box". It has no feedback tools, so it is not the link to hand over. When they submit a report, outcome: "report" returns its complete fromHuman payload: notes, files with refreshed URLs, annotated images, recordings and timed transcripts. Read these before continuing in this conversation. Other outcomes are done, superseded, cancelled, timed_out and wait_cancelled; completion and delivery status describe the handoff, rather than approval of the product or work completed by the AI.
For a full 30-minute wait in Codex, both the host tool timeout and adapter timeout must allow it. When the person requests this longer wait, add these settings to their existing stdio server entry, keeping a larger timeout if already configured and preserving its other settings:
[mcp_servers.parallelsandbox]
tool_timeout_sec = 1920
env = { PSBX_TOOL_TIMEOUT_SEC = "1920" }
Merge PSBX_TOOL_TIMEOUT_SEC into an existing env map, then reconnect the client. The adapter declares the safe review wait limit to the server. Raising waitSec alone cannot extend the client's supported limit. Without that configuration, the shorter wait returns while the review card remains available.
Timeout or cancellation leaves the card and feedback available. Resume the exact round with its reviewId:
{ "id": "<boxId>", "reviewId": "<reviewId>" }
When that round already has the person's report, the call returns it at once, whatever waitSec says: outcome: "report", reportId and the complete fromHuman, with no need for sandbox_status and sandbox_report first.
A new what replaces the previous card; reviewId resumes it. For an explicit handoff that returns immediately, set waitSec: 0. A running review call can return feedback to the current conversation.
For automatic continuation after the AI finishes, start the native conversation with parallelsandbox-agent (Quick start). A persistent supervisor uses the Codex, Claude Code or Gemini driver to own a single native writer, and registers the reviewId returned by this tool with the original conversation ID. Submitting feedback in the app resumes that same ID after the AI's turn has ended; feedback waits if a turn is still running. The resumed AI calls sandbox_report to read this complete report, and the supervisor acknowledges read only after the native turn finishes successfully. This receipt records delivery and that completed turn, rather than completion of every requested change.
For an ordinary, unregistered MCP connection, continue the original conversation yourself: press Copy message for AI in the app and paste it into that conversation, resume waiting with its original reviewId, or reread a known reportId. See native session feedback setup for models, tool permissions and recovery of the original conversation.
Pass id, what and open: you say what the card opens. The platform does not choose or detect it.
open: "web"withport: a page served on that port in the box, the port the process listens on (a dev server's 5173, for example). They open it in their own browser on their own device, which has none of the sign-ins or cookies of the browser you tested with in the box. If the product needs signing in, test it from a fresh browser session as they will, and hand over a page that signs them in by itself: for example run the box's copy with a dev-only login route that signs in a seeded test account and redirects to the start screen, and give that route's port (the card opens the port's root, so put the route there or make the root redirect to it). Otherwise put the test account and how to sign in inwhat. A desktop app whose UI is loaded from a dev server (Electron with Vite, for example) can be handed over this way too, with that dev server's port. If the port has no URL yet, it gets one in the same call: a service already declared on that port is markedweb; otherwise a service namedweb-<port>is declared and markedweb. On an older box whose boxd cannot give that port a URL, the call fails with 409 and guidance to start a new box that declares the service withweb: true.open: "box", withoutport: the card opens the box's screen, where they tap, swipe and type themselves on a desktop app (its window onDISPLAY=:99: Electron, GTK, Qt or a game) or on a phone app on a device fromsandbox_device, on Android and on the iPhone simulator alike. Keep the app running on its display or device. If nothing is on the screen and no phone is ready, the call returnsnothing is on this box's screen for a person to use: …; start the app, test it, then callsandbox_reviewagain. For a page in a browser, useopen: "web"with its port.- When the person can try it in a browser, hand over
web: it is smoother for them.
{ "id": "<boxId>", "what": "Open the app and tap Settings, then Dark mode: every screen turns dark at once. I switched it on the box screen myself.", "open": "box" }
open and port are checked before the box is touched. open missing or invalid with what (open is required with what…), open: "web" without port (open: web needs port…), port with open: "box" (port goes with open: web…) and open or port with reviewId (open and port go with what (a new review)…) each return an error. web: true in sandbox_start.services or sandbox_wire still gives a service its own URL and the app's Use it button; it does not decide what sandbox_review opens.
Details:
- The picture is a screenshot taken in the box when you call it: of that page's URL for
web, of the box's screen forbox(with a device attached, the phone's own screen). If that fails, the card goes out without one. openreports the entry you named. Awebcard keeps the page's URL from the handoff; rewiring the service afterwards does not change it. Watching the AI's live screen is a separate app entry;sandbox_takeoverlets the person operate that session for a step only they can complete.- While the person has a
boxcard open they are operating the box:sandbox_execon it answers HTTP 423 (a person is on the screen) until they leave, whilesandbox_shotof the screen still shows what they are doing (takeover: true). That is them trying it, not a broken box; do not reinstall or restart the app then. - A waiting card keeps nothing awake. The box and its devices freeze after 10 minutes with no use and are stopped by the usual idle rules (Box states), as if no review were pending. When the person opens the review, a frozen box wakes and its devices come back with it (an iPhone simulator with its apps restarted); a box that has been stopped meanwhile ends the review, and you hand the version over again on a new box.
- The card stays until the person submits a report, presses Done with this (
POST /v1/boxes/{id}/review/done), you replace it, or the box is stopped.GET /v1/boxesshows a waiting card asreview(id,what,url,shotUrl,createdAt). - With
web, their requests keep the box awake like any use of its URLs (Box states), andsandbox_scenereaches the page they have open.
Every tool and topic is listed in the tool reference.