# Environments



An **environment** is a long-lived Firecracker VM that sessions execute inside.
Binding a session to an environment gives the agent VM-backed tools — shell,
file read/write, and patch — operating on the repos cloned into that VM.

Reach for an environment when you want a VM that **persists across many
sessions**. For a one-off VM that's provisioned and torn down around a single
job, use an [on-demand run](/docs/agents/runs) instead.

## Create an environment [#create-an-environment]

<Tabs items="['Console', 'API']">
  <Tab value="Console">
    Create an environment with a name, a VM template, and the git repos to clone into
    it. The Console also lets an agent carry a **default** environment spec (template

    * repos) that its runs provision automatically — set it under the agent's
      **Environment / VM** field.
  </Tab>

  <Tab value="API">
    `POST /v1/environments` with a `name` and a `config`. Only `config.type` (always
    `cloud` in v1) is required within the config.

    ```bash
    curl https://agents.clusterbase.dev/v1/environments \
      -H "Authorization: Bearer $CLUSTER_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "web-dev",
        "config": {
          "type": "cloud",
          "template_id": "development",
          "git_repos": [{ "url": "https://github.com/acme/web", "branch": "main" }]
        }
      }'
    ```
  </Tab>
</Tabs>

## Templates [#templates]

`config.template_id` selects the infra VM image:

| Template      | Use it for                                                                         |
| ------------- | ---------------------------------------------------------------------------------- |
| `development` | A general-purpose dev VM. This is the default when `template_id` is omitted.       |
| `workspace`   | Bakes the skills repo into `/mnt/skills` — for agents that rely on bundled skills. |

## Git repos [#git-repos]

`config.git_repos` are cloned into the VM when it's first provisioned. Each repo
clones as the VM's **owner**, so private repos pull with that identity's GitHub
credentials. A repo lands at `/home/user/<name>` unless you set an explicit
`path`. Per-repo clone outcomes surface on a bound session's `cloned_repos`,
including a `warning` if a particular repo failed to clone.

```json
{ "url": "https://github.com/acme/web", "branch": "main", "path": "web" }
```

<Callout title="Networking and packages">
  In v1, `config.networking` supports only `unrestricted` — `limited` is rejected
  until network filtering ships. `config.packages` is accepted and stored but not
  yet installed (the VM provisions bare).
</Callout>

## Bind a session [#bind-a-session]

Pass `environment_id` when creating a [session](/docs/agents/sessions-and-events#create-a-session).
The VM is provisioned on the first binding and reused afterwards. The caller must
own the environment — an unknown or non-owned id returns `404`.

```bash
curl https://agents.clusterbase.dev/v1/sessions \
  -H "Authorization: Bearer $CLUSTER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "agent": "agt_3f9c2a", "environment_id": "env_9a8b7c" }'
```

## Lifecycle [#lifecycle]

List with `GET /v1/environments`, fetch one with `GET /v1/environments/{id}`.
Archiving (`POST /v1/environments/{id}/archive`) or deleting
(`DELETE /v1/environments/{id}`) tears the VM down.
