Environment variables
An environment variable reaches a sandbox from one of several layers: account-level runtime env resolved by scope, values set on the sandbox itself, secrets bound to an opaque placeholder, or env passed on a single exec. This page covers what each layer is, how conflicts resolve, and how to read the live set.
Account-level runtime env
Platform owners define environment variables once and have them inherited by sandboxes, computers, and agent runs. Runtime env is encrypted at rest and never returned as plaintext by the API, CLI, or SDKs. Responses include metadata and a short preview only.
MIOSA resolves runtime env in this order. More specific values override broader values with the same name:
| Precedence | Scope | Applies to |
|---|---|---|
| 1 | Tenant | Every workspace, project, sandbox, computer, and agent under the tenant |
| 2 | Workspace | Every project, sandbox, computer, and agent in that workspace |
| 3 | Project | Sandboxes, computers, deployments, and agent runs attributed to that project |
| 4 | Resource | Per-sandbox or per-computer env set directly on the resource |
| 5 | Run | Env passed directly to a single exec or agent run |
Each runtime env var also has a target. At the same scope, a target-specific value overrides one set to all:
| Target | Use it when |
|---|---|
all | The value is safe and useful for every runtime surface |
sandbox | The value should only appear in sandbox exec/build/agent sessions |
computer | The value should only appear in desktop computer commands and agents |
agent | The value should be injected into prompt-driven agent runs on sandboxes or computers |
deployment | Production deployment/runtime boot |
Variable names must be uppercase shell-safe names matching [A-Z][A-Z0-9_]*.
Sandbox-level env
Env vars passed at create time are injected into the VM at boot and visible to all processes. They are read-only once the sandbox is running; env.list() returns the live set.
Per-sandbox env API
The /api/v1/sandboxes/{id}/env API manages a key-value store attached to a sandbox. Variables are encrypted at rest and injected into the sandbox process environment on start. The API never returns plaintext values, only key names and metadata.
| Method | Path | Description |
|---|---|---|
GET | /api/v1/sandboxes/{id}/env | List all env vars (names only, no values) |
PUT | /api/v1/sandboxes/{id}/env | Bulk set or update env vars |
DELETE | /api/v1/sandboxes/{id}/env/{key} | Delete a single env var |
PUT is a bulk upsert: existing keys are updated, new keys are created, and keys not present in the request are left unchanged.
curl -X PUT https://api.miosa.ai/api/v1/sandboxes/sbx_abc123/env
-H "Authorization: Bearer $MIOSA_API_KEY"
-H "Content-Type: application/json"
-d '{
"vars": [
{"key": "DATABASE_URL", "value": "postgres://user:pass@host/db"},
{"key": "LOG_LEVEL", "value": "info"}
]
}' Secrets
For credentials you do not want inside the VM at all, store them as secrets. Every sandbox using a secret sees an opaque placeholder env var; the real key never lives inside the VM, and the swap happens on egress.
sandbox.secrets.set(
name="openai_key",
value="sk-proj-...",
expose_as_env="OPENAI_API_KEY",
) Inside the sandbox, os.environ["OPENAI_API_KEY"] returns an opaque token such as miosa-tok-7f2a.... When your code makes an outbound call, the MIOSA proxy on the VM’s host sees the placeholder in the Authorization header and swaps it with the real key before forwarding. Rotation is instant: every sandbox picks up the new value on its next outbound request, and the placeholder token does not change.
A secret can be scoped at tenant, workspace, user, external_user, or external_workspace, and the proxy picks the most specific match for the resource making the request.
How a value reaches exec
When a command runs, MIOSA resolves the effective environment in layers and hands it to the process:
- Inherited runtime env for the sandbox’s scope and target is materialized at boot.
- Sandbox-level env (create-time
envor the per-sandbox env API) overrides an inherited value with the same name. - Secrets appear as placeholder env vars exposed via
expose_as_env. envpassed to a single exec merges on top for that command only.
result = sbx.exec.run(
"pytest tests/ -x",
{"cwd": "/workspace", "env": {"PYTHONPATH": "/workspace"}, "timeout_sec": 120},
)