Guides

Building agent products

Guide

How do I give each of my users their own persistent agent computer?

Ask ChatGPT Ask Claude

Keep one long-lived computer per user and stop it between sessions, instead of building a fresh sandbox every time. With Sanbox, your backend creates a Computer from your product's template using your user's ID as --external-run-id, stops it when the user goes idle and resumes it when they come back, with their files, installed packages and the agent's saved state still on its disk. Snapshots and warm pools make first starts fast, and Secret Proxies keep your API keys out of every Computer.

Run this with your agent

Read https://sanbox.cloud/kb/build/one-persistent-computer-per-user.md and follow it to set up one Computer per user for my app.
If the Sanbox CLI is missing, install it with `npm install -g @sanlabs/sanbox-cli@latest`
and sign in with `sanbox login`. Show me each command before you create, stop or delete a Computer.

What does the architecture look like?

In your productIn Sanbox
The product, or one environment of itOne template: agent, model, network policy, Secret Proxies
An end userOne Computer, created with --external-run-id "user-<user-id>"
The user is activeThe Computer is running
The user is awayThe Computer is stopped: its disk is saved, its compute ends
Your backend talks to the agentA short-lived OpenCode SDK connection
A prepared starting stateA snapshot template with a warm pool

Your backend calls the Sanbox CLI or API with an organisation API key in SANBOX_API_KEY. Your users never see that key. The same pattern suits features where each end user gets their own agent, working in its own Computer.

Steps

1. Create the product template

An organisation admin creates it once, with the network policy and Secret Proxies every user's Computer should get:

sanbox templates create --name "Product agent" --type opencode-computer \
  --model-provider <provider-id> --model <model-id> \
  --network-policy policy.json --secret-proxy <proxy-name> --json
sanbox templates validate <template-id> --json

2. Create a Computer the first time a user needs one

sanbox run --template <template-id> --external-run-id "user-<user-id>" --json

Store the returned run ID with the user's record. If the request times out, repeat it with the same external ID: Sanbox returns the existing Computer instead of creating a second one. Poll sanbox runs get <run-id> --json until the run is running. Don't use --wait here; it waits for the Computer to stop.

3. Connect your backend to the agent

sanbox opencode connect <run-id> --expires 1h --json

The response holds data.url and a one-time data.access_token. Pass them to the native OpenCode SDK (@opencode-ai/sdk) as the base URL and a bearer token, then create sessions, send prompts and stream events to your user. Keep the token on your server. It stops working when it expires, is revoked, or the Computer restarts, so create a new connection after every resume. Never give SANBOX_API_KEY to the SDK.

4. Stop the Computer when the user goes idle

sanbox runs stop <run-id> --json

Stop is asynchronous, so check sanbox runs get until state is stopped. OpenCode Computers stay on until they're stopped. Sanbox doesn't stop or wake them on its own, so your app decides what idle means.

5. Resume it when the user returns

sanbox runs resume <run-id> --wait --json

Resume boots the pinned runtime fresh with the saved disk, and reuses the model the Computer started with. Then create a new connection, as in step 3.

6. Delete it when the user leaves your product

sanbox runs delete <run-id> --yes --json

Delete permanently removes the saved disk.

Make first starts fast

Do the slow setup once. Prepare one Computer with your tools and files, stop it, and capture it (this needs an organisation admin or owner). Then build a template on the snapshot and keep ready Computers in a pool:

sanbox snapshots create --run <stopped-run-id> --name product-base
sanbox templates create --name "Product agent" --snapshot product-base \
  --model-provider <provider-id> --network-policy policy.json --json
sanbox pools create --template <template-id> --name product-pool --size 3

sanbox run --template <template-id> --external-run-id "user-<user-id>" --json now takes a ready Computer when the pool has one, and starts one cold when it doesn't. A pool keeps at most five ready Computers, and they use ordinary capacity. Runs from a snapshot template take no task or model override. When you improve the base, sanbox templates update <template-id> --snapshot <new-snapshot> promotes it, and the pool's unused Computers are replaced. See how to make agent computers start instantly.

Lock down egress

Each template's network policy is deny-by-default and covers every Computer built from it. Allow only the hosts your agent needs:

{
  "default_action": "deny",
  "rules": [{ "destination": "api.example.com", "ports": [{ "from": 443, "to": 443 }] }]
}

For your own API, use a Secret Proxy instead of putting a key in the Computer. Sanbox adds the credential to matching HTTPS requests on their way out, so the agent calls the original URL and never sees the key. With "attach_run_id": true in the proxy's settings, requests also carry the run ID in X-Sanbox-Run-ID, which lets your API tell which user's Computer is calling. Your API must still authenticate the integration first, because the run ID isn't a credential.

If your users sign in with Supabase, a Computer can read their data under your RLS policies. See Supabase users with a persistent agent computer.

Which plan fits?

Sanbox is priced per organisation. Enterprise plans add professional services for custom integrations and deployment in your VPCs, and our forward-deployed engineers can build the integration into your product with you. Talk to us about the number of Computers you need.

What this doesn't do

  • No automatic idle stop or wake. Your backend calls stop and resume.
  • No memory across a stop. RAM and running processes end. Resume boots fresh from the saved disk.
  • Retry a failed resume. If a resume fails, retry it later. Don't create a new run to take over the same disk.
  • Disks are 1 to 8 GB. That holds /workspace and every installed package.
  • Your backend controls access for end users. Your users reach their Computers only through your product. Members of your Sanbox organisation with operator roles can work on its Computers, so give those roles only to people who run your service.