Guide
How do I give each of my users their own persistent agent computer?
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 product | In Sanbox |
|---|---|
| The product, or one environment of it | One template: agent, model, network policy, Secret Proxies |
| An end user | One Computer, created with --external-run-id "user-<user-id>" |
| The user is active | The Computer is running |
| The user is away | The Computer is stopped: its disk is saved, its compute ends |
| Your backend talks to the agent | A short-lived OpenCode SDK connection |
| A prepared starting state | A 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
/workspaceand 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.