Sizing and limits

Every sandbox runs on a named resource contract. Pick a size by name; the raw CPU, memory, and disk fields are compatibility inputs that must exactly match a published contract.

Sizing reference

Size namevCPURAMDiskNotes
xs12 GB10 GBLightweight scripts
small24 GB10 GBDefault for agent and build workloads
medium48 GB20 GBLarger builds and parallel tests
large816 GB40 GBHeavy test suites
xl1632 GB80 GBIntensive parallelism

Use the default small contract for Claude Code, Codex, package installation, ordinary application builds, and agent execution. Choose medium only when measured CPU, memory, or disk requirements exceed small. Raw resource fields are compatibility inputs and must exactly identify a published named contract.

Raw resource overrides (still accepted):

FieldDefaultValidation range
cpu_count21-16
memory_mb40962048-32768
disk_size_mb10240Must match the selected named contract
timeout_sec36001-86400
idle_timeout_sec0 (disabled)0-86400
always_onfalseNot required for most agent work
persistenttruePreserve sandbox state across pauses and resumes

Set always_on=True to disable timeout_sec enforcement entirely. Useful for long-lived development environments or hosted IDEs. Set idle_timeout_sec to stop an abandoned persistent session after a period of inactivity; it is off unless you set it. Set persistent=False only for one-off jobs where the filesystem should be discarded on stop or timeout.

Billing notes

Billing accrues from state = "running" until state = "paused" or state = "destroyed".

  • Running: billed at the vCPU-second + GiB-second rate for your plan
  • Paused: billed at storage rate only (disk GiB-second)
  • Destroyed: billing stops immediately

Template readiness and available sizes are reported by the catalog and can vary by environment.

Runner endpoints (opt-in preview)

The SOMA one-hop runner is an opt-in fast path for create, exec, and destroy: your SDK talks straight to the runner instead of going through the control plane first. Everything documented here keeps working unchanged whether or not you opt in.

  • https://run-us.miosa.ai works for every call. Opting in sends requests there instead of https://api.miosa.ai; EU is on the roadmap, but keys do not carry a region yet. This endpoint is unrelated to a sandbox’s placement region (us-west, us-east, us-mia).
  • A request for a sandbox that lives on a different host inside the runner fleet is forwarded internally; you almost always get an answer from run-us.miosa.ai directly (421 is a rare fallback if that internal forward fails, naming the correct URL as runner_url). For lower latency, every create response also names that sandbox’s own runner URL as a Soma-Runner-Url response header (https://<tag>.run-us.miosa.ai); official SDKs read it and call that URL directly from then on. This is an automatic optimization, not something you need to do yourself.
  • create on the runner only serves the default template, xs size, non-persistent sandboxes. A request outside that (a custom template, a snapshot, a custom cwd, persistent: true, or a larger size) answers 400 RUNNER_UNSUPPORTED_REQUEST; official SDKs send that create to https://api.miosa.ai automatically instead.
  • The runner only creates non-persistent sandboxes, so idle timeout stays off unless you set idle_timeout_sec (0-86400 s). timeout_sec (default 3600, max 86400) caps lifetime, and always_on=True disables the timeout entirely for long-lived sandboxes and hosted IDEs.
  • exec defaults to a 30 second timeout, same as the control plane. POST /api/v1/sandboxes/{id}/exec/stream streams stdout/stderr as server-sent events, ending with an exit event.
  • destroy responses include cpu_ms and lifetime_ms for this sandbox’s usage.
  • 429 runtime_busy (with Retry-After: 0) means this runner is at its admission limit; retry the request. 429 rate_limited is a per-key or per-tenant rate limit, same semantics as the control plane. 503 feed_stale means the runner’s key and policy data is too old to accept new creates; its existing sandboxes keep working.
  • Runners serve HTTP/3 (QUIC) first and fall back to HTTP/2 automatically if QUIC is blocked on your network. Official SDKs handle the fallback for you.

A raw HTTP client can use either the regional URL or the per-sandbox URL named in the Soma-Runner-Url header:

curl -i -X POST https://run-us.miosa.ai/api/v1/sandboxes 
  -H "Authorization: Bearer $MIOSA_API_KEY" 
  -H "Content-Type: application/json" 
  -d '{"template_id": "miosa-sandbox"}'
# Soma-Runner-Url: https://3.run-us.miosa.ai

curl https://3.run-us.miosa.ai/api/v1/sandboxes/3a1b2c3d-1111-2222-3333-444444444444 
  -H "Authorization: Bearer $MIOSA_API_KEY"

Every runner response adds a Server-Timing header breaking auth, pool, and exec time down in milliseconds.

Errors specific to the runner path

StatusCodeCause
401unauthorizedThe key is unknown or revoked in this runner’s in-memory table.
403forbiddenThe tenant is not enabled for this path, is suspended, or the project is not allowed.
400RUNNER_UNSUPPORTED_REQUESTThis create shape is not served by the runner (see above). Official SDKs retry it against https://api.miosa.ai.
429rate_limitedPer-key or per-tenant rate limit, same semantics as the control plane.
429runtime_busyThis runner is at its admission limit (Retry-After: 0). Retry the request; run-us.miosa.ai resolves to every runner in the region, so a retry can land on a different one.
503feed_staleThis runner’s key and policy data is older than its freshness limit (Retry-After: 0). Creates are refused; its existing sandboxes keep working.
421misdirectedRare: the internal forward to the sandbox’s own host failed. The body names the correct URL again as runner_url. Follow it once; do not retry the original URL.

The full endpoint contract (request and response bodies) is unchanged by runner mode; only the host you send them to changes. See the Sandboxes API for the control-plane reference.

Was this page helpful?