# Environments

> What a moatbox environment gives each new space, how versions and upgrades work, and what the default environment and safe mode do.

An environment is a team-level template for moatbox spaces. It lists the repositories, variables, secret files, setup script, AI profile and integrations that a space starts with. Each save creates a new numbered version, and each space records the version it runs. You manage environments under **Integrations → Environments** in the dashboard (`https://app.moatbox.dev/environments`). For spaces themselves, see [Spaces](https://docs.moatbox.dev/spaces.md).

Owners and admins create and change environments. Members can read them.

## What an environment holds

| Section | What the space gets | Applies to running spaces? |
|---------|---------------------|----------------------------|
| **Repositories** | GitHub repositories (`owner/name`, optional branch), cloned into `/workspace/<name>` at first setup | Only in a space that has not run setup yet |
| **Variables** | Environment variables in every shell, the setup script and runs | Yes |
| **Secret files** | Files written under `/workspace` with mode 600 | Yes |
| **Setup script** | A bash script that runs once per space | Only in a space that has not run setup yet |
| **AI** | An AI profile: a placeholder and base URL for each model key; the gateway adds the real key | Yes |
| **Integrations** | Which of the team's connected integrations reach the space | Yes |
| **Space key** | An API key for the space itself, in `MOATBOX_SPACE_KEY` | Yes |

The **What a new space gets** panel on the environment page sums up the saved version.

### Repositories

Enter each repository as `owner/name` (a `https://github.com/` prefix and `.git` suffix are fine) and an optional branch. moatbox clones it into `/workspace/<name>` through the gateway, so no GitHub token lands in the space. If `/workspace/<name>` already exists, moatbox skips the clone. Two repositories cannot clone into the same folder.

### Variables

Variables reach every SSH shell, the setup script and agent runs. Tick **Hidden** to mask a value in the dashboard: moatbox then shows only its last four characters, and you replace it with **Replace**. A hidden value is still readable inside the space. **Paste .env** adds several variables at once.

A variable name matches `[A-Za-z_][A-Za-z0-9_]*`, up to 128 characters. moatbox reserves some names and refuses them: system names such as `PATH`, `HOME` and `SHELL`, proxy and CA-bundle variables, `GH_TOKEN`, the AWS key variables, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `CODEX_API_KEY`, names starting with `MOATBOX_` or `GIT_CONFIG`, and the credential names of built-in integrations.

For an API key, use an AI profile or an integration instead of a variable. The gateway then adds the key and the space never holds it.

### Secret files

A secret file has a path relative to `/workspace` (no leading `/`, no `..`) and its contents. moatbox writes it with mode 600, and writes it again at each wake and upgrade, so an edit made inside the space to a file still in the environment does not last. Remove a file from the environment and moatbox deletes it from the space, unless someone edited it there; an edited file stays.

### Setup script

moatbox runs the setup script with bash in `/workspace`, after it clones the repositories, with the environment's variables set. A failed clone stops setup before the script, and the clones and script together get 30 minutes. Setup runs once per space: the first time the space receives an environment version with repositories or a setup script. A space created on an environment without either runs them later, when an upgrade or a move first brings them. To see its state (`queued`, `running`, `ok`, `failed` with the exit code, or `interrupted`) and its output, click a space under **Spaces** on the environment page. moatbox keeps the first 1 MiB of output, and the dashboard shows the last 64 KiB of that.

### AI

**Profile** picks an AI profile from the team's **AI** page, or **Team default**. Spaces get a placeholder and a base URL for each key and custom API on the profile; the gateway adds the real key. Agent keys and custom APIs saved in an environment before AI profiles existed still work through the gateway. You can remove them, but new ones go on a profile.

### Integrations

**Every connected integration** gives the space each integration the team connected on the **Integrations** page. Turn it off to pick from `aws`, `cloudflare`, `discord`, `github`, `gmail`, `hetzner`, `linear`, `notion`, `slack` and `stripe`. The keys stay in the gateway. See [Integrations](https://docs.moatbox.dev/integrations.md).

### Space key

With **Space key** on, moatbox issues each space its own API key, scoped to that one space, and exports `MOATBOX_SPACE_KEY`, `MOATBOX_SPACE` and `MOATBOX_API` in its shells. By default the key can do `space.read`, `file.read` and `run`. You can add `exec`, `file.write`, `space.sleep`, `space.update`, `snapshot.read`, `snapshot.write` and `deploy`. The key shows on the **API keys** page and you can revoke it there or from the space's panel on the environment page. Turning **Space key** off revokes it. See [API keys](https://docs.moatbox.dev/api-keys.md).

## Limits

| Item | Limit |
|------|-------|
| Environment name | 1 to 40 characters of `a-z`, `0-9`, `-` and `_`, starting with a letter or digit |
| Repositories | 20 |
| Variables | 200, each value up to 32 KiB |
| Secret files | 50, each up to 64 KiB, 256 KiB in total |
| Custom APIs | 20 |
| Setup script | 64 KiB |
| One save | 1 MiB of JSON |

## Safe for third parties

**Safe for third parties** (under **Access**) prepares an environment for spaces you hand to someone outside the team. With it on:

- no integrations reach the spaces
- private repositories and the space key are off
- the gateway offers AI only through a profile you pick on the environment, plus custom APIs saved on the environment before AI profiles existed; **Team default** turns into **None**
- moatbox drops agent keys saved on the environment

Variables, secret files, public repositories and the setup script still apply. The environments list marks such an environment "safe for third parties".

## Versions and upgrades

Each **Save as vN** creates version N. Spaces stay on the version they have until you upgrade them:

- **Upgrade** next to a space, or **Upgrade all**, on the environment page.
- **Apply to running spaces** in the notice after a save.
- **Apply changes to running spaces** (under **Access**): with it on, each save moves every space on the environment to the new version.

An upgrade changes variables, secret files, the AI profile, integrations and the space key in running spaces. Open shells keep the old values until you reopen them. Repository and setup-script changes do not run again in a space that has run setup; see [Setup script](#setup-script). If a sleeping or unreachable space misses the update, moatbox retries.

The **Versions** list shows who saved each version and how many spaces run it. Click an older version to see what changed between it and the current one, marked "live" or "new spaces".

## The default environment

New spaces start on the team's default environment unless the create form names another. A team with no environment gets one named `base`, marked default, the first time someone lists environments or creates a space. **Make default** on another environment moves the mark.

You cannot delete the default environment. Deleting any other environment hides it from new spaces; spaces on it keep their version.

## Create, copy and move

- **New environment** on the Environments page takes a name and **Start from**: **Empty** or **Copy of** an existing environment, including its hidden values.
- **Move a space here…** on an environment page puts an existing space on that environment's current version. Its repositories and setup script run only if the space has never run setup; see [Setup script](#setup-script).
- A [fork](https://docs.moatbox.dev/spaces.md#forks) keeps its parent's environment and version.

## API

| Method and path | Purpose |
|-----------------|---------|
| `GET /api/v1/teams/<team>/environments` | List environments |
| `POST /api/v1/teams/<team>/environments` | Create one: `{"name": "ci", "copy_from": "base"}` |
| `GET /api/v1/teams/<team>/environments/<env>` | Read the current version, its spaces and versions |
| `PUT /api/v1/teams/<team>/environments/<env>` | Save a new version |
| `PATCH /api/v1/teams/<team>/environments/<env>` | Rename, or make default with `{"default": true}` |
| `DELETE /api/v1/teams/<team>/environments/<env>` | Delete |
| `GET /api/v1/teams/<team>/environments/<env>/diff?from=1&to=3` | Compare two versions |
| `POST /api/v1/teams/<team>/environments/<env>/upgrade` | Upgrade spaces: `{"spaces": ["my-space"]}`, or `{}` for all |
| `GET`, `PUT /api/v1/spaces/<space>/environment` | Read or change a space's environment |

`<env>` takes the environment's name or ID. To pick an environment at creation, pass `"environment": "<name>"` to `POST /api/v1/teams/<team>/spaces`.
