> ## 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.

# Helix Cloud and managed agents

> Launch Helix on Helix Cloud, run managed agents, control running sessions, and deploy managed agents 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>

The Python SDK starts Helix on Helix Cloud. It launches a task or an interactive session, runs a
managed agent, sends input to a running session, stops it, checkpoints it and restores it. It also
lists, inspects, deploys, activates and retires managed agents.

To follow a session's output, see [Read session output](#read-session-output).

Session and model calls are on `client.helix_sessions`. Managed agent calls are on `client.managed_agents`.
The token exchange, sandbox providers and presets 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.

## Create the clients

Session and model calls take a short-lived sandbox token. Managed agent calls take 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; managed agent calls
exchange = platform.sandbox.create_sandbox_token(SandboxTokenRequest(workspace_id="<workspace-id>"))

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

`expires_in` is in seconds. Exchange the API key again after that. `platform.workspaces.list_workspaces()`
returns the workspace ID as `workspaces[].id_`. See
[Get a sandbox token](/sdk/python/environments#get-a-sandbox-token) for the refusals.

Managed agent calls act in the workspace of a workspace API key. With an organization API key, also send
the `x-workspace-id` header; with a personal API key, send `x-organization-id` and `x-workspace-id`. Set
them as `headers` on an `httpx.Client` passed as `http_client`.

## Models

`get_helix_models` lists the models a launch can name and the workspace default.
`set_helix_default_models` sets the ordered default list; the first entry is the default.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import HelixDefaultModelsRequest, 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.helix_sessions.get_helix_models()
print([model.id_ for model in listing.models], listing.default)

client.helix_sessions.set_helix_default_models(
    HelixDefaultModelsRequest(models=[listing.models[0].id_])
)
```

| Response field | What it is |
| - | - |
| `models[].id_` | The `provider/model` value a launch takes as `model`. |
| `models[].display_name` | The model's display name. |
| `defaults` | The stored default list, in order. |
| `default` | The model a launch that names none uses, or `None`. With `None`, such a launch is refused with 428 `NO_PROVIDER_CONFIGURED`. |
| `unmapped` | Active LLM providers that contribute no models. |

The list comes from your [LLM providers](/sdk/python/providers). `set_helix_default_models`
refuses a model that is not in the list with 422. `HelixDefaultModelsRequest(models=[])` clears the
defaults.

## Launch a task

`launch_helix_session` allocates a sandbox and starts Helix in it. For a task, the same as
`mutagent helix -p "<task>"`, pass `mode=Mode.HEADLESS` and the task as `-p` in `args`. The session ends
when the task is done.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import HelixLaunchRequest, Mode, 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)

session = client.helix_sessions.launch_helix_session(
    HelixLaunchRequest(
        mode=Mode.HEADLESS,
        args=["-p", "Evaluate the support agent against its last 50 traces."],
        model="<provider>/<model>",
        environment="ci",
        sandbox_provider="mutagent-cloud",
    )
)
print(session.reference, session.status)
```

| Field | What it does |
| - | - |
| `mode` | `Mode.HEADLESS` runs the task in `args` and ends. `Mode.INTERACTIVE` keeps the session running and reads commands. Default: `Mode.INTERACTIVE`. |
| `arm` | `HelixArm.CLASSIC` (the default), `HelixArm.PRIME` or `HelixArm.AGENT`. |
| `args` | Arguments for Helix, such as `["-p", "<task>"]`. |
| `model` | A `models[].id_` from [Models](#models). Omitted: the workspace default. |
| `environment` | An [Environment](/sdk/python/environments) to load. 404 when the workspace has none by that name. |
| `env` | Variables for this launch only, as `{"NAME": "value"}`. They override the Environment's values of the same name. |
| `cwd` | The working directory in the sandbox. |
| `preset` | A preset name from `list_sandbox_presets`. Omitted: the default preset. |
| `sandbox_provider` | A sandbox provider name from `list_sandbox_providers`. Omitted: the default sandbox provider. An unknown name is refused before a sandbox starts. |
| `agent` | A `HelixLaunchAgent` to run. See [Run a managed agent](#run-a-managed-agent). |

Refusals: 404 for an unknown Environment, 422 for a model outside the list (the body names the list),
422 when `model` and a `--model` in `args` disagree, 428 `NO_PROVIDER_CONFIGURED` when no model is given
and the workspace has no default.

## The launch receipt

`launch_helix_session` returns the receipt as soon as the session starts.

| Field | What it is |
| - | - |
| `reference` | The `hs1_` session reference. Every call below takes it. |
| `session_id` | The session's ID in its sandbox. |
| `status` | The session state the sandbox reported. |
| `mode` | The mode the session started in: `Mode.HEADLESS` or `Mode.INTERACTIVE`. |
| `arm` | The arm the session started on: `HelixArm.CLASSIC`, `HelixArm.PRIME` or `HelixArm.AGENT`. |
| `sandbox_id` | The sandbox the session runs in. |
| `preset` | The preset used. |
| `agent` | For a managed agent: `agent.slug` and `agent.revision`. |

The reference points at one session in one sandbox. After a restore, the session has a new reference.

## Start an interactive session

With `mode=Mode.INTERACTIVE` the session keeps running and reads one JSON command per line. Send the task as a
`prompt` command with [`send_helix_session_input`](#send-input).

```python theme={null}
import json

from mutagent import Mutagent
from mutagent.models import HelixLaunchRequest, HelixSessionInputRequest, Mode, 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)

session = client.helix_sessions.launch_helix_session(
    HelixLaunchRequest(mode=Mode.INTERACTIVE, environment="ci")
)

client.helix_sessions.send_helix_session_input(
    session.reference,
    HelixSessionInputRequest(
        line=json.dumps({"type": "prompt", "id": "task-1", "message": "Explain the evaluation steps."})
    ),
)
print(session.reference)
```

A sandbox stops after 15 minutes with no activity. An interactive session is checkpointed before it stops. See
[Sessions](/helix/cloud/sessions).

## Run a managed agent

Pass `agent` to run a [managed agent](/helix/cloud/managed-agents). `environment` selects the slot and
loads that Environment. Without `revision`, the slot's active revision runs.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import HelixLaunchAgent, HelixLaunchRequest, 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)

session = client.helix_sessions.launch_helix_session(
    HelixLaunchRequest(
        agent=HelixLaunchAgent(slug="invoice-pricing"),
        environment="prod",
        args=["-p", "Price the invoices in the inbox."],
    )
)
print(session.reference, session.agent.slug, session.agent.revision)
```

| `agent` field | What it does |
| - | - |
| `slug` | The managed agent's slug. |
| `revision` | A revision number such as `3`, or `"latest"` for the newest validated revision, active or not. Omitted: the slot's active revision. |

The agent's package sets the prompt, tools, skills and model. With `agent`:

* `mode` omitted runs headless when `args` has a `-p` task, and otherwise the package's
  mode.
* `arm` other than `agent`, `model`, `cwd`, and any `args` other than `["-p", "<task>"]` are refused
  with 422.

| Refusal | When |
| - | - |
| 404 | Unknown agent or slot, or an Environment that no longer exists. |
| 409 `MANAGED_AGENT_ARCHIVED` | The agent is archived. |
| 409 `MANAGED_AGENT_SLOT_RETIRED` | The slot is retired. |
| 422 | No active revision, no such validated revision, a model outside the workspace list, a headless run without a task, or a sandbox provider that cannot receive the package. |

All refusals happen before a sandbox starts.

## List sessions

`list_helix_sessions` lists the workspace's sessions, live and ended, newest activity first.

```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)

cursor = None
while True:
    page = client.helix_sessions.list_helix_sessions(limit=100, cursor=cursor)
    for row in page.sessions:
        print(row.reference, row.status, row.arm, row.mode, row.agent)
    cursor = page.next_cursor
    if cursor is None:
        break
```

| Field | What it is |
| - | - |
| `reference` | The session reference. It also works for ended sessions. |
| `sandbox_id` | The sandbox the session ran or runs in. |
| `status` | `live`, `ended`, `stopped-for-idling` or `restored`. |
| `exit_code` | On an `ended` session, the exit code, or `None`. |
| `arm`, `mode` | What ran and how. Absent when unknown. |
| `agent` | For a managed agent, `slug:vN`. |
| `snapshot_id` | On a `restored` session, the checkpoint it came from. |
| `created_at`, `last_activity_at` | `datetime` values: when the session started and last did something. |
| `seq_high_water` | The highest output number the session produced. |

`limit` is 1 to 500 (default 100). Pass `next_cursor` back as `cursor`; it is `None` on the last page.

## Send input

`send_helix_session_input` writes one JSON command to an interactive session. `line` is exactly one serialised JSON
object with no newline.

```python theme={null}
import json

from mutagent import Mutagent
from mutagent.models import HelixSessionInputRequest, 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.helix_sessions.send_helix_session_input(
    "hs1_<…>",
    HelixSessionInputRequest(line=json.dumps({"type": "get_state", "id": "state-1"})),
)
print(result.accepted)
```

`accepted` is `True` when the line reached the session. Whether the agent accepted the command appears in
the session's output. Refusals: 400 when `line` is not one JSON object, 409 when the session is not
running.

## Close input

`close_helix_session_input` closes the session's input, as end-of-file on stdin. It is not a signal: the
agent finishes and its remaining output still arrives. Calling it twice is safe.

```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)

print(client.helix_sessions.close_helix_session_input("hs1_<…>", {})["closed"])
```

`close_helix_session_input` returns a `dict`, not a model. 422 when the sandbox cannot close input; no
signal is sent instead.

## Stop a session

`signal_helix_session` signals the session's process. The sandbox keeps running.

```python theme={null}
from mutagent import Mutagent
from mutagent.models import HelixSessionSignalRequest, HelixSignal, 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.helix_sessions.signal_helix_session(
    "hs1_<…>", HelixSessionSignalRequest(signal=HelixSignal.SIGINT)
)
print(result.signalled)
```

`signal` is `HelixSignal.SIGTERM` (the default) or `HelixSignal.SIGINT`. Both stop the session's Helix
process. `signalled` is `True` when the signal reached a running process. 409 when the session has already ended.

## Checkpoint a session

`checkpoint_helix_session` saves an interactive session's conversation, and its working directory when
that can be captured. A headless session is not checkpointed.

```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)

checkpoint = client.helix_sessions.checkpoint_helix_session("hs1_<…>", {})
print(checkpoint.snapshot_id, checkpoint.message_count, checkpoint.not_captured)
```

| Field | What it is |
| - | - |
| `snapshot_id` | The checkpoint ID. A restore takes it. |
| `message_count` | Messages saved. Never 0. |
| `bytes_`, `sha256` | Size and SHA-256 of the saved conversation. |
| `harness_session_id` | Helix's own session ID. It stays the same across a restore. |
| `workspace_bytes`, `workspace_files` | Size and file count of the saved working directory, or `None` when none was saved. |
| `not_captured` | One line per part that was not saved, with the reason. Empty means everything was saved. |

Refusals: 409 when there is nothing to save yet (the session has not completed a turn), 422 when the
sandbox cannot be checkpointed.

## List checkpoints

`list_helix_session_checkpoints` lists the checkpoints of the sandbox the session runs in, newest first.

```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 snapshot in client.helix_sessions.list_helix_session_checkpoints("hs1_<…>").snapshots:
    print(snapshot.id_, snapshot.session_id, snapshot.message_count, snapshot.captured_at)
```

Each row has `id_`, `session_id`, `harness_session_id`, `bytes_`, `sha256`, `message_count` and `captured_at`.
The list covers every session the sandbox has run.

## Restore a session

`restore_helix_session` starts a new sandbox from a checkpoint and continues the conversation. The old
sandbox does not need to exist.

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

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)

restored = client.helix_sessions.restore_helix_session(
    "hs1_<…>",
    HelixRestoreRequest(
        snapshot_id="<snapshot-id>",
        environment="ci",
        on_workspace_drift=WorkspaceDriftPolicy.WARN,
    ),
)
print(restored.reference, restored.not_restored, restored.workspace_drift.status)
```

| Body field | What it does |
| - | - |
| `snapshot_id` | The checkpoint to restore. Omitted: the newest checkpoint that can be restored in full. |
| `environment` | The Environment to load. Omitted: the Environment the session started with. |
| `on_workspace_drift` | When the conversation refers to files the new sandbox lacks: `WorkspaceDriftPolicy.WARN` (the default) restores and reports them, `WorkspaceDriftPolicy.REFUSE` fails with 409, `WorkspaceDriftPolicy.SKIP` does not check. |
| `partial` | `True` also restores conversation written after the checkpoint. It can end on a tool call without a result; the agent then sees that call as failed. |

| Response field | What it is |
| - | - |
| `reference` | The new session reference. Use it from now on. |
| `restored` | Always `True`. A failed restore is an error. |
| `snapshot_id` | The checkpoint used. |
| `not_restored` | One line per part that did not come back, with the reason. |
| `workspace_drift` | `status` is `clean`, `drifted` (`missing` lists the files) or `unchecked`. |
| `skipped_snapshots` | Newer checkpoints skipped because they could not be restored in full. |

Refusals: 404 when the checkpoint is not in the workspace or the Environment does not exist, 409
`MANAGED_AGENT_RESTORE_UNSUPPORTED` for a session that ran a managed agent, 422 when the restored
conversation does not match the checkpoint.

## Read session output

To follow a session's output, use the CLI with the reference from the receipt:

```bash theme={null}
mutagent helix session attach <reference>
```

The session's result also shows in `list_helix_sessions`: `status` and `exit_code`.

## List managed agents

`list_helix_agents` lists the workspace's managed agents and their slots. The API key authenticates it.

```python theme={null}
from mutagent import Mutagent

client = Mutagent(server_url="https://api.mutagent.io")  # reads MUTAGENT_API_KEY

page = client.managed_agents.list_helix_agents()
for agent in page.data:
    print(agent.slug, agent.status, agent.model)
    for slot in agent.deployments:
        print("  ", slot.environment or "default", slot.active_revision, slot.enabled)
print(page.next_cursor)
```

| Field | What it is |
| - | - |
| `slug`, `name`, `description` | The agent. |
| `model` | The `provider/model` of the revision a slot last activated. |
| `status` | `active`, or `archived`. Archived agents are listed only with `include_archived=True`. |
| `deployments` | The slots: `environment` (`None` is the default slot), `active_revision`, `generation`, `enabled` (`False` once retired). |
| `next_cursor` | Pass back as `cursor` for the next page, or `None`. |

## Inspect a managed agent

`get_helix_agent` returns an agent's revisions, slots and the sessions launched from it.

```python theme={null}
from mutagent import Mutagent

client = Mutagent(server_url="https://api.mutagent.io")  # reads MUTAGENT_API_KEY

detail = client.managed_agents.get_helix_agent(
    "invoice-pricing", revision_limit=20, session_limit=20
)
for revision in detail.revisions.data:
    print(f"v{revision.revision}", revision.model, revision.mode, revision.validation_status)
for session in detail.sessions:
    print(session.reference, session.environment, session.revision)
```

| Field | What it is |
| - | - |
| `agent` | The agent, as in the list. |
| `revisions.data` | `revision`, `model`, `mode` (`Mode.INTERACTIVE` or `Mode.HEADLESS`), `validation_status` (`uploaded`, `validated` or `failed`), and the digests `source_digest`, `artifact_digest`, `archive_digest`. `revisions.next_cursor` pages them with `revision_cursor`. |
| `deployments` | The slots, as in the list. |
| `sessions` | Sessions launched from the agent, newest first: `reference`, `sandbox_id`, `environment`, `revision`, `created_at`. |

## Deploy a managed agent

`deploy_helix_agent` uploads a package as a revision and, by default, activates it in the slot. The
package is the archive that `mutagent agent pack` writes; `pack` also prints its `archiveDigest`,
`artifactDigest` and `archiveSize`. The slug must be the `name` in the agent's `agent.md`.

```bash theme={null}
mutagent agent pack invoice-pricing/agent.md --output invoice-pricing.tgz
```

```python theme={null}
import base64
import uuid

from mutagent import Mutagent
from mutagent.models import DeployAgentRequest

client = Mutagent(server_url="https://api.mutagent.io")  # reads MUTAGENT_API_KEY

with open("invoice-pricing.tgz", "rb") as file:
    archive = file.read()

result = client.managed_agents.deploy_helix_agent(
    "invoice-pricing",
    DeployAgentRequest(
        archive_base64=base64.b64encode(archive).decode("ascii"),
        archive_digest="<archiveDigest printed by pack>",
        artifact_digest="<artifactDigest printed by pack>",
        archive_size=len(archive),
        environment="prod",
        idempotency_key=str(uuid.uuid4()),
    ),
)
print(f"v{result.revision.revision}", result.revision_created, result.operation.stage)
```

| Body field | What it does |
| - | - |
| `archive_base64` | The archive, base64-encoded. The request is limited to 16 MiB. |
| `archive_digest`, `artifact_digest`, `archive_size` | The values `pack` printed. |
| `environment` | The slot's Environment. Omitted: the default slot, which loads no Environment. |
| `activate` | `False` stores the revision without making it active. Default: `True`. |
| `expected_generation` | Deploy only if the slot is still at this generation. |
| `idempotency_key` | 8 to 128 characters. A retry with the same key returns the first result. |

The response has `agent`, `revision`, `revision_created` (`False` when the same package was already a
revision), `deployment` (the slot) and `operation`.

Nothing is stored when a deploy is refused:

| Refusal | When |
| - | - |
| 404 | The Environment does not exist. |
| 409 | An agent that is not a managed agent already uses the slug. |
| 422 | The package name is not the slug, a secret binding is required, the model is not in the workspace list, or no sandbox provider can receive the package. |
| 428 | The model's LLM provider is not configured in the workspace. |

Deploying the slug of an archived agent un-archives it. `get_helix_agent_capabilities` returns the
largest accepted archive as `max_archive_bytes` and the sandbox providers that can receive a package as
`staging_sandbox_providers`.

## Activate a revision

`activate_helix_agent` makes a revision the slot's active revision. An older revision is a rollback. It
also re-enables a retired slot. Running sessions keep the revision they started with.

```python theme={null}
import uuid

from mutagent import Mutagent
from mutagent.models import ActivateAgentRequest

client = Mutagent(server_url="https://api.mutagent.io")  # reads MUTAGENT_API_KEY

result = client.managed_agents.activate_helix_agent(
    "invoice-pricing",
    ActivateAgentRequest(revision=2, environment="prod", idempotency_key=str(uuid.uuid4())),
)
print(result.deployment.active_revision, result.deployment.enabled, result.operation.stage)
```

`revision` is the revision number: `v2` is `2`. The same model, Environment, secret binding and sandbox
provider checks as deploy apply. 404 when the slot or revision does not exist. 409
`MANAGED_AGENT_ARCHIVED` for an archived agent; only deploy brings it back.

## Retire a slot

`retire_helix_agent` disables a slot. New launches from it are refused; running sessions finish.

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

client = Mutagent(server_url="https://api.mutagent.io")  # reads MUTAGENT_API_KEY

result = client.managed_agents.retire_helix_agent(
    "invoice-pricing", RetireAgentRequest(environment="prod")
)
print(result.deployment.enabled)
```

Pass `RetireAgentRequest()` to retire the default slot. [Activate a revision](#activate-a-revision) to enable the slot
again.

## Operation status

Deploy and activate return an `operation`. `get_helix_agent_operation` reads it again by ID.

```python theme={null}
from mutagent import Mutagent

client = Mutagent(server_url="https://api.mutagent.io")  # reads MUTAGENT_API_KEY

operation = client.managed_agents.get_helix_agent_operation("<operation-id>")
print(operation.operation_kind, operation.stage, operation.error)
```

| Field | What it is |
| - | - |
| `operation_kind` | `deploy`, `activate` or `retire`. |
| `stage` | `accepted`, `validating`, `validated`, `preparing`, `ready`, `active`, `retired` or `failed`. |
| `result`, `error` | The outcome, or `None`. |
| `idempotency_key` | The key the operation was started with. |

## Errors

A refused call raises `SDKError`. `status_code` is the HTTP status and `body` is the JSON the server
returned, as text. Refusals that name a code carry it in `code`.

```python theme={null}
import json

from mutagent import Mutagent, SDKError
from mutagent.models import HelixLaunchAgent, HelixLaunchRequest, 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.helix_sessions.launch_helix_session(
        HelixLaunchRequest(agent=HelixLaunchAgent(slug="missing"), args=["-p", "Run."])
    )
except SDKError as err:
    body = json.loads(err.body)
    print(err.status_code, body.get("code"), body["message"])
```

## Async

`AsyncMutagent` has the same calls on `client.helix_sessions`, `client.managed_agents` and `client.sandbox`; `await`
each one.

Helix Cloud creates and stops the sandbox for each session.

The same work from the command line: [mutagent helix session](/cli/commands/helix-session) and
[mutagent agent](/cli/commands/agent).


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