Docs · Agents

Build a platform: a sandbox per user

Products can give each of their users (or each project) a sandbox: persistent files, a coding agent that works inside it, a private preview URL. The terms allow it. The pieces:

  1. A key for your backend. froog api-key create backend --preset ci creates, starts, forks and deletes only what it created, and can't touch billing or other keys. Store it as FROOG_API_KEY. For a component that serves one user, make a key limited to that user's sandbox: --sandbox user-42.
  2. Nothing of yours in user sandboxes. Create them with "environment": false (no account variables, repos, secret files or in-sandbox froog key), and give each one what it needs with its own variables: the user's API keys, a tenant id.
    POST /v1/sandboxes
    {"name": "user-42", "from": "web-stack", "environment": false,
     "env": {"TENANT_ID": "42", "ANTHROPIC_API_KEY": "<the user's key>"}}
  3. A template. Install your stack once in a sandbox and save it (froog snapshot base --name web-stack). Every user's sandbox starts from it with "from": "web-stack". Put house rules for the agents (AGENTS.md, CLAUDE.md, skills, MCP servers) in it too.
  4. Know when it's ready. Create answers 202 at once. The sandbox is usable when its state is running (poll GET /v1/sandboxes/{name}, or take the sandbox.running webhook).
  5. Run the agent. POST /v1/sandboxes/{name}/prompts {"prompt", "agent", "model"} queues a task for one of ten harnesses with the user's keys (a missing key answers 400 provider_not_configured). Stream its events into your UI with Accept: text/event-stream. Later prompts continue the same conversation, and /steer and /interrupt map to your UI's send and stop buttons.
  6. Show the result. POST /urls {"port": 3000} gives a private preview URL (it carries a token, so treat it like a password). Use "public": true to embed it in an iframe on your site, since browsers may block the private URL's cookie there. Hand files to the user's browser with signed download and upload URLs.
  7. Keep only what you must. Monitoring off keeps no command history, and zero data retention erases each sandbox at stop.

Patterns and cost

Running time is billed per second, only while a sandbox runs ($0.0274 an hour for default), and a stopped sandbox costs no running time. So:

  • Always on, one sandbox per project or per user: the simplest, and $20 a month for a default one. A user's projects can share one sandbox, each in its own folder on its own port.
  • Stop when unused: every hour a sandbox is stopped is an hour you don't pay for, so a user who works two hours a day costs a twelfth of one who keeps it on. Its auto-stop timer (ttl_secs, an hour after each start by default) stops it. While the user works, push the deadline back (PATCH a new ttl_secs, or froog extend NAME --hours 2), and start the sandbox when they return, in about 15 seconds. Its disk is kept 14 days (save a snapshot to keep it longer). Processes don't survive a stop: start your dev server again, or run it from the setup script.
  • Disposable per task: start from the template, run, read the output, delete. You pay only for the seconds it ran: 20 default runs of 2 hours each cost $1.10.

Starts are limited to 20 a minute, 100 an hour and 500 a day per account, and an account runs as many sandboxes at once as its plan allows (2, 5, 10 or 25, more on request): GET /v1/limits shows where you are.