# Environments & secrets

> Decide what every new sandbox starts with — variables, secret files, GitHub repositories and credentials — with versions so changes never surprise a running sandbox.

An **environment** is the starting kit a sandbox receives when it is created. It bundles:

- **Variables** — a `.env`-style list, exported to every process in the sandbox.
- **Secret files** — files written into the home directory (a service-account JSON, `~/.npmrc`, a kubeconfig).
- **Repositories** — GitHub repos cloned into `/home/user` with a base branch and optional setup script.
- **Credential switches** — whether the sandbox gets your GitHub token, your agent-provider logins and its own Sandboxer key.

Every account starts with one environment called `base`, which is the default. Add more for different projects or audiences.

## Variables and secret files

Manage them on the dashboard under **Environment**, or from the CLI:

```bash
sbx env set-var base STRIPE_KEY=sk_test_123
sbx env rm-var base STRIPE_KEY
sbx env set-file base .config/gcloud/key.json --from ./key.json
cat ./local.env | sbx env set-file base my-app/.env
sbx env rm-file base my-app/.env
```

Inside the sandbox, variables are in `/etc/sandboxer/env` and exported by `/etc/profile.d/sandboxer.sh`, so they reach login shells, `sbx exec`, systemd services that load the file, and agents. Secret-file paths are relative to `/home/user`.

### Per-sandbox values

`env` on create (or `-e` on the CLI) adds variables to **one** sandbox, on top of its environment. On a name clash the per-sandbox value wins.

```bash
sbx new -e TENANT_ID=acme -e FEATURE_X=1
```

```json
{ "env": { "TENANT_ID": "acme", "FEATURE_X": "1" } }
```

Limits: names match `[A-Za-z_][A-Za-z0-9_]{0,127}`; at most 100 variables and 64 KB in total.

Reserved names that you cannot set: `SANDBOXER_ID`, `SANDBOXER_TOKEN`, `SANDBOXER_API_URL`, `SANDBOXER_SUBDOMAIN`, `SANDBOXER_CLI_TOKEN`, `AGENT_ID`, `ENVIRONMENT_ID`, `PRODUCT_MODE`, `SERVICE_PREVIEW_TOKEN`. Sandboxer sets the first four for you (see [Machines](/docs/machines#inside-the-sandbox)).

## Repositories

Connect GitHub once on the dashboard, then attach repos to an environment:

```bash
sbx env add-repo base acme/web --branch main
sbx env rm-repo base acme/web
```

New sandboxes clone them into `/home/user/<repo>` with a token that lets `git push` and `gh pr create` work — as long as the environment passes GitHub credentials.

## Credential switches

| Switch | What the sandbox gets |
| - | - |
| `--github` | Your GitHub token and repository clones |
| `--secrets` | The environment's variables and secret files |
| `--sandbox-credentials` | A Sandboxer key scoped to this sandbox, so it can host ports and read its own snapshots |
| `--agents-credentials` | Your provider keys and logins for Claude Code, Codex and the other harnesses |
| `--safe-for-third-parties` | **Master switch.** When on, the sandbox gets nothing of yours and the switches above are ignored |

```bash
sbx env set base --github true --secrets true --agents-credentials true
sbx env set customer-demos --safe-for-third-parties true
```

### Sandboxes for other people: `noEnv`

If a sandbox is going to someone else — a customer, an end user, an untrusted agent — create it with `noEnv` (or on an environment marked safe for third parties). It receives no variables, files or credentials of yours and cannot act on your account or your other sandboxes. Its `SANDBOXER_TOKEN` can only read that one sandbox and host its ports. SSH, the desktop, snapshots and hosting still work. Give it secrets of its own with `env`.

```bash
sbx new --no-env -e THEIR_API_KEY=…
```

A fork of a `noEnv` sandbox is always `noEnv`. Resuming with `--no-env` is one-way: your secrets are scrubbed from the restored disk and never come back.

## Versions and upgrades

Every change to an environment creates a new **immutable version**. A sandbox is pinned to the version it started with and keeps it — through stops, resumes and forks — until you upgrade it:

```bash
sbx env list                 # versions and how many sandboxes are on each
sbx env info base
sbx env upgrade base         # move all sandboxes of `base` to the latest version
```

On upgrade, running sandboxes get the new configuration immediately (anything the new version no longer includes is **deleted** from their disk first); stopped sandboxes pick it up when they resume.

The sandbox's `environment` and `environmentVersion` fields tell you exactly what it holds.

## Named environments

```bash
sbx env new staging
sbx env rename staging prod
sbx env default prod         # used when a create names no environment
sbx env rm staging           # soft delete; pinned sandboxes keep running
sbx new --environment prod
```

> **Warning** `--environment` and `--env` are different things. `--environment prod` chooses the kit; `--env KEY=value` sets one variable on one sandbox.

## Account secrets via the API

The simplest integration is `GET`/`POST /secrets`, which reads or replaces the default environment's `.env` contents and secret files in one call. Updates are pushed to running sandboxes on that environment.

```bash
curl -sS -X POST https://sandboxer.com/api/v1/secrets \
  -H "Authorization: Bearer $SANDBOXER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"envContents":"OPENAI_API_KEY=sk-…\nDATABASE_URL=postgres://…","secretFiles":[{"path":".config/sa.json","contents":"{…}"}]}'
```

For named environments use the `/environments` endpoints — see the [API reference](/docs/api).
