> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mutagent.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Environments and sandbox providers

> List, create, update and delete workspace Environments, and list sandbox providers and presets, with the Python SDK.

<Note>
  **Early access.** Cloud sessions and managed agent runs are not open to every account yet: we are
  letting accounts in gradually while we test. They run in a cloud sandbox operated by Mutagent, so
  there is nothing to host. A sandbox with nothing to do for 15 minutes stops; send the session a
  message and it wakes up, delivers your message and carries on in the same conversation.
</Note>

An Environment holds the variables and secrets your cloud sessions' tools need, such as a GitHub token
or a database URL. The Python SDK lists, describes, creates, updates, replaces and deletes
Environments, and lists the sandbox providers and presets a Helix Cloud launch can name.

An Environment has variables and secrets only. It has no tools: tools come with the agent, see
[Tools and skills](/platform/managed-agents/tools-and-skills). Model keys do not go in an Environment;
they come from your [LLM providers](/sdk/python/providers).

Environment calls are on `client.environments`. The token exchange, sandbox provider and preset calls
are on `client.sandbox`. Request bodies and responses are typed
models from `mutagent.models`; read response fields as attributes. These pages require
`mutagent-sdk` 0.4.1.

## Get a sandbox token

Environment and sandbox provider calls take a short-lived sandbox token, not your API key. Exchange
the API key for a token with `create_sandbox_token`. Pass the token
as `bearer_token` to a second client. A client takes either `api_key` or `bearer_token`, not both.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import SandboxTokenRequest

SERVER_URL = "https://api.mutagent.io"

platform = Mutagent(server_url=SERVER_URL)  # reads MUTAGENT_API_KEY
exchange = platform.sandbox.create_sandbox_token(SandboxTokenRequest(workspace_id="<workspace-id>"))

client = Mutagent(server_url=SERVER_URL, bearer_token=exchange.token)
print(f"token valid for {exchange.expires_in} seconds")
```

| Response field | What it is |
| - | - |
| `token` | The sandbox token. |
| `expires_in` | Seconds until the token expires. Exchange the API key again after that. Do not store the token. |

`workspace_id` is the workspace's ID; `platform.workspaces.list_workspaces()` returns it as
`workspaces[].id_`. The API key must be allowed to create resources in that workspace, and a key limited
to one workspace or organization can only get a token inside it. Refusals: 401, 403, 422, 429.

## List Environments

`list_environments` returns every Environment in the workspace.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import SandboxTokenRequest

SERVER_URL = "https://api.mutagent.io"
token = Mutagent(server_url=SERVER_URL).sandbox.create_sandbox_token(
    SandboxTokenRequest(workspace_id="<workspace-id>")
).token
client = Mutagent(server_url=SERVER_URL, bearer_token=token)

for environment in client.environments.list_environments().environments:
    print(environment.name, len(environment.vars_), len(environment.secrets))
```

Each Environment has this shape. No call returns a stored value.

| Field | What it is |
| - | - |
| `name` | The Environment name, such as `ci` or `prod`. |
| `vars_` | The variables, each with `name` and `fingerprint`. |
| `secrets` | The secrets, each with `name` and `fingerprint`. Secrets are stored encrypted. |
| `created_at`, `updated_at` | ISO timestamps, or `None`. |

A fingerprint is the first 8 hex characters of the SHA-256 of the value. Compare fingerprints to check
that a stored value is the one you hold.

## Describe one Environment

`get_environment` returns one Environment in the same shape.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import SandboxTokenRequest

SERVER_URL = "https://api.mutagent.io"
token = Mutagent(server_url=SERVER_URL).sandbox.create_sandbox_token(
    SandboxTokenRequest(workspace_id="<workspace-id>")
).token
client = Mutagent(server_url=SERVER_URL, bearer_token=token)

ci = client.environments.get_environment("ci")
print([f"{entry.name} {entry.fingerprint}" for entry in ci.vars_])
```

404 when the workspace has no Environment with that name.

## Create an Environment or set entries

`update_environment` creates the Environment when it does not exist, and otherwise
changes only the entries you name. A string value sets an entry. `None` removes it. Entries you do not
name are kept.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import EnvironmentPatchRequest, SandboxTokenRequest

SERVER_URL = "https://api.mutagent.io"
token = Mutagent(server_url=SERVER_URL).sandbox.create_sandbox_token(
    SandboxTokenRequest(workspace_id="<workspace-id>")
).token
client = Mutagent(server_url=SERVER_URL, bearer_token=token)

ci = client.environments.update_environment(
    "ci",
    EnvironmentPatchRequest(
        vars_={"DATABASE_URL": "<database-url>", "OLD_FLAG": None},
        secrets={"GITHUB_TOKEN": "<github-token>"},
    ),
)
print(ci.name, ci.updated_at)
```

It returns the Environment as `get_environment` does.

## Replace an Environment

`replace_environment` sets the whole Environment. Entries the body does not name are
deleted, secrets included.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import EnvironmentReplaceRequest, SandboxTokenRequest

SERVER_URL = "https://api.mutagent.io"
token = Mutagent(server_url=SERVER_URL).sandbox.create_sandbox_token(
    SandboxTokenRequest(workspace_id="<workspace-id>")
).token
client = Mutagent(server_url=SERVER_URL, bearer_token=token)

prod = client.environments.replace_environment(
    "prod",
    EnvironmentReplaceRequest(
        vars_={"DATABASE_URL": "<database-url>"},
        secrets={"GITHUB_TOKEN": "<github-token>"},
    ),
)
print(len(prod.vars_), len(prod.secrets))
```

### Rules for both calls

| Rule | Refusal |
| - | - |
| The Environment name matches `^[A-Za-z0-9._-]{1,64}$`. | 422 |
| A variable or secret name matches `^[A-Z_][A-Z0-9_]*$`. A value is a string, or `None` to remove the entry when you set entries. | 422 |
| One Environment holds at most 64 KiB. | 422 |
| A variable named like an LLM provider key, such as `ANTHROPIC_API_KEY`, is refused unless you pass `allow_provider_key=QueryFlag.VALUE_1`, the value `"1"`. `QueryFlag` is in `mutagent.models`. With it, the value replaces the workspace key for runs that load this Environment. | 409 |

## Delete an Environment

`delete_environment` deletes the Environment and its secrets.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import SandboxTokenRequest

SERVER_URL = "https://api.mutagent.io"
token = Mutagent(server_url=SERVER_URL).sandbox.create_sandbox_token(
    SandboxTokenRequest(workspace_id="<workspace-id>")
).token
client = Mutagent(server_url=SERVER_URL, bearer_token=token)

result = client.environments.delete_environment("ci")  # returns a dict
print(result["deleted"], result["name"])
```

It returns `{"deleted": True, "name": ...}`. 404 when there is no Environment with that name, including
a delete you retry. Sessions already running keep the values they started with. A later launch that
names the deleted Environment is refused with 404.

## List sandbox providers

`list_sandbox_providers` lists the sandbox providers a launch can name, and the default.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import SandboxTokenRequest

SERVER_URL = "https://api.mutagent.io"
token = Mutagent(server_url=SERVER_URL).sandbox.create_sandbox_token(
    SandboxTokenRequest(workspace_id="<workspace-id>")
).token
client = Mutagent(server_url=SERVER_URL, bearer_token=token)

sandbox_providers = client.sandbox.list_sandbox_providers()
print(sandbox_providers.names, sandbox_providers.default)
```

| Response field | What it is |
| - | - |
| `names` | The sandbox provider names. |
| `default` | The sandbox provider a launch uses when it names none, or `None`. |

Pass a name as `sandbox_provider` when you [launch a session](/sdk/python/helix-cloud#launch-a-task).
The SDK has no call that adds or configures a sandbox provider. See
[Sandbox providers](/helix/cloud/sandbox-providers).

## List presets

`list_sandbox_presets` lists the presets a launch can name as `preset`, and the default.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import SandboxTokenRequest

SERVER_URL = "https://api.mutagent.io"
token = Mutagent(server_url=SERVER_URL).sandbox.create_sandbox_token(
    SandboxTokenRequest(workspace_id="<workspace-id>")
).token
client = Mutagent(server_url=SERVER_URL, bearer_token=token)

listing = client.sandbox.list_sandbox_presets()
for preset in listing.presets:
    print(preset.name, preset.arch, preset.provider, preset.environment)
print(listing.default)
```

| Field | What it is |
| - | - |
| `presets[].name` | The preset name. |
| `presets[].description` | What the preset runs. |
| `presets[].arch` | The CPU architecture. |
| `presets[].provider` | The sandbox provider the preset runs on, when it names one. |
| `presets[].environment` | The Environment the preset loads, when it names one. |
| `default` | The preset a launch uses when it names none, or `None`. |

## Errors

A refused call raises `SDKError`. `status_code` is the HTTP status and `body` is the JSON the server
returned, as text, with `error` and `message`.

```python theme={null}
import json

from mutagent import Mutagent, SDKError
from mutagent.models import SandboxTokenRequest

SERVER_URL = "https://api.mutagent.io"
token = Mutagent(server_url=SERVER_URL).sandbox.create_sandbox_token(
    SandboxTokenRequest(workspace_id="<workspace-id>")
).token
client = Mutagent(server_url=SERVER_URL, bearer_token=token)

try:
    client.environments.get_environment("missing")
except SDKError as err:
    print(err.status_code, json.loads(err.body)["message"])
```

## Async

`AsyncMutagent` has the same calls on `client.environments` and `client.sandbox`; `await` each one.

The same Environments from the command line: [mutagent env](/cli/commands/env).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.