> Documentation index: [/llms.txt](/llms.txt). Every page as one file: [/llms-full.txt](/llms-full.txt).

# Build an environment

Build an environment [#build-an-environment]

Write each test case as one sentence, let the platform turn it into a simulated person, add checks, and save the result.

Endpoints [#endpoints]

All paths start with `/api/v1/diagnostics` and need `X-Space-Slug`.

| Method   | URL                                     | Does                                                                                                                                                                              | Auth          |
| -------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `POST`   | `/agents/{agent_id}/suggest-scenarios/` | Draft simulated people for the agent; nothing is saved; billed                                                                                                                    | Key or bearer |
| `GET`    | `/check-catalog/`                       | Ready-made checks: `[{id, type, label, default_params, …}]`                                                                                                                       | Key or bearer |
| `POST`   | `/agents/{agent_id}/suggest-checks/`    | Draft checks for the agent; nothing is saved; billed                                                                                                                              | Key or bearer |
| `POST`   | `/kits/`                                | Create an environment; `201`                                                                                                                                                      | Key or bearer |
| `GET`    | `/kits/`                                | List environments                                                                                                                                                                 | Key or bearer |
| `GET`    | `/kits/{kit_id}/`                       | Read one                                                                                                                                                                          | Key or bearer |
| `PATCH`  | `/kits/{kit_id}/`                       | Change `name`, `description`, `dataset`, `file_bucket` or `assertions`                                                                                                            | Key or bearer |
| `DELETE` | `/kits/{kit_id}/`                       | Delete one; `204`                                                                                                                                                                 | Key or bearer |
| `GET`    | `/kits/{kit_id}/export/`                | Download it as a ZIP; `?include_dataset=false` leaves the cases out                                                                                                               | Key or bearer |
| `POST`   | `/kits/import/`                         | Create one from an exported ZIP (multipart `file`); `?check=true` validates without writing                                                                                       | Key or bearer |
| `POST`   | `/kits/{kit_id}/clone/`                 | Copy it, optionally for another agent: `{"agent_id", "name"}`                                                                                                                     | Key or bearer |
| `POST`   | `/kits/{kit_id}/publish/`               | Publish a copy to a catalog: `{"scope_visibility": "space" \| "global", "keep_agent", "name", "description", "acknowledge_shared_files"}`; `global` is for platform admins; `201` | Key or bearer |

* An export carries the cases and the checks, not the documents: attach the files again after an import.
* A clone keeps the checks and documents.
* A clone keeps the simulated people only for the same agent or one promoted from it; otherwise `PATCH` its `dataset`.

Scenario request fields [#scenario-request-fields]

| Field                                                       | Rule                                                                                                                                    |
| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `cases`                                                     | 1–25 `{id, description, file_ids}`. One scenario comes back per case, with the same `id`. `id` is unique, up to 80 characters           |
| `bucket`                                                    | `[{file_id, description}]`: every file a case holds, with a short description of the document                                           |
| `conversations`                                             | Without `cases`: how many scenarios to write, 1–25, default 3                                                                           |
| `conversation_ids`                                          | Without `cases`: up to 200 of the agent's chats to base the scenarios on                                                                |
| `window_start`, `window_end`                                | Without `cases` and `conversation_ids`: base the scenarios on the chats in this window; both or neither. `max_conversations` samples it |
| `persona_guidance`, `engagement_guidance`, `extra_guidance` | How the people behave; never what the agent must do                                                                                     |
| `diagnostic_effort`                                         | `low`, `medium` (default) or `high`                                                                                                     |

Without `cases`, `conversation_ids` or a window, scenarios are written from the agent's configuration alone.

Scenario fields [#scenario-fields]

A scenario can also be written by hand, with no billed call, and saved directly as a `simulated_user`.

| Field       | Rule                                                                                                                                                  |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`        | Required; unique within the environment                                                                                                               |
| `persona`   | Required: who writes to the agent                                                                                                                     |
| `context`   | Required: their situation                                                                                                                             |
| `goal`      | Required: what they want from the conversation                                                                                                        |
| `opening`   | Required: their first message                                                                                                                         |
| `facts`     | Details the person knows and can give when asked                                                                                                      |
| `max_turns` | Messages the person sends at most, 1–20; default 10. A run plays every case with one count: the highest of its cases, unless the run sets `max_turns` |

Build and save an environment [#build-and-save-an-environment]

1. Upload each document a case needs with `POST /api/v1/agents-v2/files/upload/` ([Attach files](../configurable-agents/run-and-stream#attach-files)); its `id` is the `file_id`.
2. Draft the simulated people:

   ```bash
   curl -X POST "$CENTRAL_HUB_URL/api/v1/diagnostics/agents/42/suggest-scenarios/" \
     -H "X-API-Key: $ALO_API_KEY" \
     -H "X-Space-Slug: $WORKSPACE_SLUG" \
     -H "Content-Type: application/json" \
     -d '{
       "cases": [{"id": "deadline", "description": "A bid manager wants the exact deadline of the tender.", "file_ids": ["<file id>"]}],
       "bucket": [{"file_id": "<file id>", "description": "The tender rules, 28 pages"}],
       "diagnostic_effort": "low"
     }'
   ```

   The response is `{scenarios, abstained, note, …}`. Each scenario holds `id`, `persona`, `goal`, `opening` and the `facts` the platform filled in. `abstained: true` means nothing could be built from what was sent; `note` says why.
3. Pick checks: from `GET /check-catalog/`, from `POST /agents/42/suggest-checks/` with `{"diagnostic_effort": "low"}` (the response is `{assertions, abstained, note}`), or write them. A check is `{id, type, label, description, params}`; a check in your own words is `"type": "llm_judge"` with `"params": {"prompt": "PASS if … FAIL if …"}`.
4. Save the environment. Each `dataset` row wraps one scenario from step 2, unchanged, as `simulated_user`:

   ```bash
   curl -X POST "$CENTRAL_HUB_URL/api/v1/diagnostics/kits/" \
     -H "X-API-Key: $ALO_API_KEY" \
     -H "X-Space-Slug: $WORKSPACE_SLUG" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "Tender questions",
       "agent_id": 42,
       "dataset": [{"simulated_user": {"id": "deadline", "persona": "A bid manager at a construction firm", "context": "Preparing a bid for a public tender", "goal": "Learn the exact submission deadline", "opening": "When is the deadline for this tender?"}}],
       "file_bucket": [{"file_id": "<file id>", "description": "The tender rules, 28 pages"}],
       "assertions": [{"id": "cites-deadline", "type": "llm_judge", "label": "Cites the deadline", "description": "", "params": {"prompt": "PASS if the answer gives the deadline stated in the tender rules. FAIL otherwise."}}]
     }'
   ```

   The response holds the environment's `id`, used as `kit_id` by the gym and diagnoses.

Troubleshooting [#troubleshooting]

| Response                                                              | Cause                                                      | Fix                                                              |
| --------------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------- |
| `422` `cases hold files that are not in the bucket: …`                | A case's `file_ids` names a file missing from `bucket`     | Add the file to `bucket`                                         |
| `422` `case ids must be unique: …`                                    | Two cases share an `id`                                    | Rename one                                                       |
| `422` `Documents in a catalog environment are readable by everyone …` | Files added to a catalog environment                       | Send `acknowledge_shared_files=true` to share them               |
| `422` `This window projects to ~… tokens …`                           | The window holds too many chats to read; nothing was spent | Narrow the window, or set `max_conversations`                    |
| `422` `Model '…' is not configured in this space …`                   | The effort level's model is not enabled in the workspace   | Pick another `diagnostic_effort`, or write the scenarios by hand |
