Environments
A named execution context binding one sandbox + one repo policy + a set of secret-name bindings into something a thread can reference, durable and inspectable within a house. threads.environment_id carries an FK with on delete set null, and the thread row keeps a snapshot of the environment — so later env edits or teardown don’t rewrite a thread’s history.
environments { id, house_id (FK cascade), author_id, name, sandbox_id (required at row level), default_repo, allowed_repos[], github_installation_id, secret_bindings: jsonb [{name, required}] # resolved against house secrets at dispatch}POST /api/environments with sandbox_id omitted auto-provisions a box on the env’s runtime. Daytona (the default) creates a fresh house-scoped sandbox via DAYTONA_API_KEY — no pi install (a daytona box ships a shell; delegate_task spins its own per-run box). runtime: 'sprite' instead provisions a sprite (name <env-name>-<short-id>, requires the house’s SPRITES_TOKEN) and runs setupLifecycle to install pi before writing the row. Bindings store names, not values — see secrets for resolution. Sandbox pi defaults to defaultModelRef (llm-keys) — bind OPENROUTER_API_KEY. Provider-specific keys (ANTHROPIC_API_KEY, OPENAI_API_KEY, …) still work paired with a matching thread.config.model override.
| Endpoint | Auth | Notes |
|---|---|---|
GET /api/environments?house_id=<uuid> | house member | list |
GET /api/environments/<id> | house member | fetch one |
POST /api/environments | member-write | auto-provisions on the runtime (daytona default) when sandbox_id omitted |
PATCH /api/environments/<id> | member-write | partial update |
DELETE /api/environments/<id> | owner-only | soft delete |
GitHub App integration: when github_installation_id is set, dispatch mints a short-lived installation access token scoped to allowed_repos and injects it as GITHUB_TOKEN. Two browser-only endpoints (/api/github/installations, /api/github/installations/:id/repos) require a GitHub OAuth provider session — not callable with an arbe API key. Server needs GITHUB_APP_ID (numeric) + GITHUB_APP_PRIVATE_KEY (PEM RSA) as wrangler secrets; absent → 501 on listing endpoints, dispatch silently skips token minting (the environment still works, just without GITHUB_TOKEN).
CLI (all commands operate on the active house, set via arbe house select):
arbe env list [--json]arbe env view <name-or-id> # name (case-insensitive) or UUIDarbe env create <name> --sandbox <id> --secret OPENROUTER_API_KEY [--optional-secret NICE_KEY]arbe env bind-secret <name|id> <SECRET_NAME> [--optional] # idempotent — same --optional is no-op,arbe env unbind-secret <name|id> <SECRET_NAME> # different value upgrades/downgradesarbe env delete <name|id>--secret (required) and --optional-secret (warn-only at dispatch) are repeatable on create. Dispatch with --env: arbe --env work thread entries create <ref> "fix the bug" — --env is a root-level option that resolves the environment by name or ID and uses its sandbox_id, overriding any -s flag. Sandboxes are created once and reused across dispatches.
Code: packages/core/schemas/environment.ts (EnvironmentRowSchema), packages/core/environments.ts, apps/www/src/routes/api/environments/.
See daytona runtime, system/sandbox-sprite, system/secrets, system/dispatch, runtime.