> ## 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 TypeScript 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 TypeScript 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.helixSessions`. Managed agent calls are on `client.managedAgents`.
The token exchange, sandbox providers and presets are on `client.sandbox`.

## Create the client

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 `createSandboxToken`, then create a client that holds both. Each
call sends the credential it needs.

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;

const { token, expiresIn } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });

const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });
console.log(`token valid for ${expiresIn} seconds`);
```

`expiresIn` is in seconds. Exchange the API key again after that. `client.workspaces.listWorkspaces()`
returns the workspace ID as `workspaces[].id`. See
[Get a sandbox token](/sdk/typescript/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`.
Every call takes request options as its last argument, for example
`{ headers: { 'x-workspace-id': '<workspace-id>' } }`.

## Models

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

const listing = await client.helixSessions.getHelixModels();
console.log(listing.models.map((model) => model.id), listing.default);

await client.helixSessions.setHelixDefaultModels({ models: [listing.models[0].id] });
```

| Response field | What it is |
| - | - |
| `models[].id` | The `provider/model` value a launch takes as `model`. |
| `models[].displayName` | The model's display name. |
| `defaults` | The stored default list, in order. |
| `default` | The model a launch that names none uses, or `null`. With `null`, 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/typescript/providers). `setHelixDefaultModels`
refuses a model that is not in the list with 422. `models: []` clears the defaults.

## Launch a task

`launchHelixSession` 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.

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';
import { Mode } from '@mutagent/sdk/models';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

const session = await client.helixSessions.launchHelixSession({
  mode: Mode.Headless,
  args: ['-p', 'Evaluate the support agent against its last 50 traces.'],
  model: '<provider>/<model>',
  environment: 'ci',
  sandboxProvider: 'mutagent-cloud',
});
console.log(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/typescript/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 `listSandboxPresets`. Omitted: the default preset. |
| `sandboxProvider` | A sandbox provider name from `listSandboxProviders`. Omitted: the default sandbox provider. An unknown name is refused before a sandbox starts. |
| `agent` | A managed agent to run. See [Run a managed agent](#run-a-managed-agent). |

`Mode` and `HelixArm` are exported by `@mutagent/sdk/models`.

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

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

| Field | What it is |
| - | - |
| `reference` | The `hs1_` session reference. Every call below takes it. |
| `sessionId` | The session's ID in its sandbox. |
| `status` | The session state the sandbox reported. |
| `mode` | The mode the session started in: `headless` or `interactive`. |
| `arm` | The arm the session started on: `classic`, `prime` or `agent`. |
| `sandboxId` | The sandbox the session runs in. |
| `preset` | The preset used. |
| `agent` | For a managed agent: `{ slug, 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 [`sendHelixSessionInput`](#send-input).

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';
import { Mode } from '@mutagent/sdk/models';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

const session = await client.helixSessions.launchHelixSession({ mode: Mode.Interactive, environment: 'ci' });

await client.helixSessions.sendHelixSessionInput({
  reference: session.reference,
  body: {
    line: JSON.stringify({ type: 'prompt', id: 'task-1', message: 'Explain the evaluation steps.' }),
  },
});
console.log(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.

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

const session = await client.helixSessions.launchHelixSession({
  agent: { slug: 'invoice-pricing' },
  environment: 'prod',
  args: ['-p', 'Price the invoices in the inbox.'],
});
console.log(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

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

let cursor: string | undefined;
do {
  const page = await client.helixSessions.listHelixSessions({ limit: 100, cursor });
  for (const row of page.sessions) {
    console.log(row.reference, row.status, row.arm, row.mode, row.agent, row.lastActivityAt);
  }
  cursor = page.nextCursor;
} while (cursor);
```

| Field | What it is |
| - | - |
| `reference` | The session reference. It also works for ended sessions. |
| `sandboxId` | The sandbox the session ran or runs in. |
| `status` | `live`, `ended`, `stopped-for-idling` or `restored`. |
| `exitCode` | On an `ended` session, the exit code, or `null`. |
| `arm`, `mode` | What ran and how. Absent when unknown. |
| `agent` | For a managed agent, `slug:vN`. |
| `snapshotId` | On a `restored` session, the checkpoint it came from. |
| `createdAt`, `lastActivityAt` | When the session started and last did something. |
| `seqHighWater` | The highest output number the session produced. |

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

## Send input

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

const { accepted } = await client.helixSessions.sendHelixSessionInput({
  reference: 'hs1_<…>',
  body: { line: JSON.stringify({ type: 'get_state', id: 'state-1' }) },
});
console.log(accepted);
```

`accepted: true` means 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

`closeHelixSessionInput` 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.

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

const { closed } = await client.helixSessions.closeHelixSessionInput({ reference: 'hs1_<…>', body: {} });
console.log(closed);
```

422 when the sandbox cannot close input; no signal is sent instead.

## Stop a session

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';
import { HelixSignal } from '@mutagent/sdk/models';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

const { signalled } = await client.helixSessions.signalHelixSession({
  reference: 'hs1_<…>',
  body: { signal: HelixSignal.Sigint },
});
console.log(signalled);
```

`signal` is `HelixSignal.Sigterm` (the default) or `HelixSignal.Sigint`. Both stop the session's Helix process. `signalled: true` means
the signal reached a running process. 409 when the session has already ended.

## Checkpoint a session

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

const checkpoint = await client.helixSessions.checkpointHelixSession({ reference: 'hs1_<…>', body: {} });
console.log(checkpoint.snapshotId, checkpoint.messageCount, checkpoint.notCaptured);
```

| Field | What it is |
| - | - |
| `snapshotId` | The checkpoint ID. A restore takes it. |
| `messageCount` | Messages saved. Never 0. |
| `bytes`, `sha256` | Size and SHA-256 of the saved conversation. |
| `harnessSessionId` | Helix's own session ID. It stays the same across a restore. |
| `workspaceBytes`, `workspaceFiles` | Size and file count of the saved working directory, or `null` when none was saved. |
| `notCaptured` | 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

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

const { snapshots } = await client.helixSessions.listHelixSessionCheckpoints({ reference: 'hs1_<…>' });
for (const snapshot of snapshots) {
  console.log(snapshot.id, snapshot.sessionId, snapshot.messageCount, snapshot.capturedAt);
}
```

Each row has `id`, `sessionId`, `harnessSessionId`, `bytes`, `sha256`, `messageCount` and `capturedAt`.
The list covers every session the sandbox has run.

## Restore a session

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';
import { WorkspaceDriftPolicy } from '@mutagent/sdk/models';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

const restored = await client.helixSessions.restoreHelixSession({
  reference: 'hs1_<…>',
  body: { snapshotId: '<snapshot-id>', environment: 'ci', onWorkspaceDrift: WorkspaceDriftPolicy.Warn },
});
console.log(restored.reference, restored.notRestored, restored.workspaceDrift.status);
```

| Body field | What it does |
| - | - |
| `snapshotId` | 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. |
| `onWorkspaceDrift` | When the conversation refers to files the new sandbox lacks: `Warn` (the default) restores and reports them, `Refuse` fails with 409, `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. |
| `snapshotId` | The checkpoint used. |
| `notRestored` | One line per part that did not come back, with the reason. |
| `workspaceDrift` | `status` is `clean`, `drifted` (`missing` lists the files) or `unchecked`. |
| `skippedSnapshots` | 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 `listHelixSessions`: `status` and `exitCode`.

## List managed agents

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const client = new Mutagent({
  serverURL: 'https://api.mutagent.io',
  security: { apiKey: process.env.MUTAGENT_API_KEY! },
});

const { data, nextCursor } = await client.managedAgents.listHelixAgents({ includeArchived: false });
for (const agent of data) {
  console.log(agent.slug, agent.status, agent.model);
  for (const slot of agent.deployments) {
    console.log('  ', slot.environment ?? 'default', slot.activeRevision, slot.enabled);
  }
}
console.log(nextCursor);
```

| 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 `includeArchived: true`. |
| `deployments[]` | The slots: `environment` (`null` is the default slot), `activeRevision`, `generation`, `enabled` (`false` once retired). |
| `nextCursor` | Pass back as `cursor` for the next page, or `null`. |

## Inspect a managed agent

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const client = new Mutagent({
  serverURL: 'https://api.mutagent.io',
  security: { apiKey: process.env.MUTAGENT_API_KEY! },
});

const detail = await client.managedAgents.getHelixAgent({
  slug: 'invoice-pricing',
  revisionLimit: 20,
  sessionLimit: 20,
});
for (const revision of detail.revisions.data) {
  console.log(`v${revision.revision}`, revision.model, revision.mode, revision.validationStatus);
}
for (const session of detail.sessions) {
  console.log(session.reference, session.environment, session.revision);
}
```

| Field | What it is |
| - | - |
| `agent` | The agent, as in the list. |
| `revisions.data[]` | `revision`, `model`, `mode` (`interactive` or `headless`), `validationStatus` (`uploaded`, `validated` or `failed`), and the digests `sourceDigest`, `artifactDigest`, `archiveDigest`. `revisions.nextCursor` pages them with `revisionCursor`. |
| `deployments[]` | The slots, as in the list. |
| `sessions[]` | Sessions launched from the agent, newest first: `reference`, `sandboxId`, `environment`, `revision`, `createdAt`. |

## Deploy a managed agent

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

```typescript theme={null}
import { readFile } from 'node:fs/promises';
import { Mutagent } from '@mutagent/sdk';

const client = new Mutagent({
  serverURL: 'https://api.mutagent.io',
  security: { apiKey: process.env.MUTAGENT_API_KEY! },
});

const archive = await readFile('invoice-pricing.tgz');
const result = await client.managedAgents.deployHelixAgent({
  slug: 'invoice-pricing',
  body: {
    archiveBase64: archive.toString('base64'),
    archiveDigest: '<archiveDigest printed by pack>',
    artifactDigest: '<artifactDigest printed by pack>',
    archiveSize: archive.byteLength,
    environment: 'prod',
    idempotencyKey: crypto.randomUUID(),
  },
});
console.log(`v${result.revision.revision}`, result.revisionCreated, result.operation.stage);
```

| Body field | What it does |
| - | - |
| `archiveBase64` | The archive, base64-encoded. The request is limited to 16 MiB. |
| `archiveDigest`, `artifactDigest`, `archiveSize` | 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`. |
| `expectedGeneration` | Deploy only if the slot is still at this generation. |
| `idempotencyKey` | 8 to 128 characters. A retry with the same key returns the first result. |

The response has `agent`, `revision`, `revisionCreated` (`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. `getHelixAgentCapabilities` returns the
largest accepted archive as `maxArchiveBytes` and the sandbox providers that can receive a package as
`stagingSandboxProviders`.

## Activate a revision

`activateHelixAgent` 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.

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const client = new Mutagent({
  serverURL: 'https://api.mutagent.io',
  security: { apiKey: process.env.MUTAGENT_API_KEY! },
});

const { deployment, operation } = await client.managedAgents.activateHelixAgent({
  slug: 'invoice-pricing',
  body: { revision: 2, environment: 'prod', idempotencyKey: crypto.randomUUID() },
});
console.log(deployment.activeRevision, deployment.enabled, 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

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const client = new Mutagent({
  serverURL: 'https://api.mutagent.io',
  security: { apiKey: process.env.MUTAGENT_API_KEY! },
});

const { deployment } = await client.managedAgents.retireHelixAgent({
  slug: 'invoice-pricing',
  body: { environment: 'prod' },
});
console.log(deployment.enabled);
```

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

## Operation status

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

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';

const client = new Mutagent({
  serverURL: 'https://api.mutagent.io',
  security: { apiKey: process.env.MUTAGENT_API_KEY! },
});

const operation = await client.managedAgents.getHelixAgentOperation({
  operationId: '<operation-id>',
});
console.log(operation.operationKind, operation.stage, operation.error);
```

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

## Errors

A refused call throws a subclass of `MutagentError`. `statusCode` is the HTTP status and `body` is the
JSON the server returned. Refusals that name a code carry it in `code`.

```typescript theme={null}
import { Mutagent } from '@mutagent/sdk';
import { MutagentError } from '@mutagent/sdk/models/errors';

const serverURL = 'https://api.mutagent.io';
const apiKey = process.env.MUTAGENT_API_KEY!;
const { token } = await new Mutagent({ serverURL })
  .sandbox.createSandboxToken({ apiKey }, { workspaceId: '<workspace-id>' });
const client = new Mutagent({ serverURL, security: { apiKey, bearerAuth: token } });

try {
  await client.helixSessions.launchHelixSession({ agent: { slug: 'invoice-pricing' }, args: ['-p', 'Run.'] });
} catch (err) {
  if (err instanceof MutagentError) {
    const body = JSON.parse(err.body);
    console.log(err.statusCode, body.code, body.message);
  } else {
    throw err;
  }
}
```

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.