Configuration
- Core
- Auth
- Credentials
- Egress
- Budgets and backstops
- Limits
- Kubernetes
- Notifications
- Memory
- Per-agent CLI knobs
- Warden (set per session by the orchestrator)
Everything is an environment variable on the orchestrator. Warden’s own variables are set by the orchestrator per session and are listed at the bottom for reference — you don’t set them.
Core
| Variable | Default | Purpose |
|---|---|---|
TERRA_RUNNER |
docker |
Sandbox backend: docker · k8s · local. |
TERRA_IMAGE |
terrarium-sandbox |
Sandbox image (registry/tag) the orchestrator launches. |
TERRA_MODEL |
sonnet |
Default model alias for new sessions. |
TERRA_HOST / TERRA_PORT |
127.0.0.1 / 8900 |
API bind. |
TERRA_RUNTIME_DIR / TERRA_LOGS_DIR |
~/.terrarium / logs/ |
State + event-log roots. |
TERRA_NETWORK |
terrarium-net |
Docker network prefix; each session gets its own bridge off it. |
TERRA_DOCKER_RUNTIME |
— | Set to runsc for gVisor. |
Auth
| Variable | Default | Purpose |
|---|---|---|
TERRA_TOKEN |
— | Admin bearer token. Also the fallback KEK. |
TERRA_ALLOW_NO_AUTH |
0 |
1 permits a non-loopback bind with no token. Dangerous — the API is then an unauthenticated admin surface. |
TERRA_CORS_ORIGINS |
— | Comma-separated allow-list, used only when a token is set. Empty = no cross-origin access. |
TERRA_METRICS_PUBLIC |
0 |
1 allows an unauthenticated /metrics scrape. |
The orchestrator refuses to start on a non-loopback bind with no
TERRA_TOKENunlessTERRA_ALLOW_NO_AUTH=1. That is deliberate: the failure mode it prevents is an open admin API, and a warning in a log nobody reads is not a control.
Credentials
| Variable | Default | Purpose |
|---|---|---|
ANTHROPIC_API_KEY |
— | API-key mode. |
TERRA_KEK |
— | Key that seals the credential and secret stores at rest. Falls back to TERRA_TOKEN. |
TERRA_CREDS |
~/.claude/.credentials.json |
Seed path for the subscription credential. |
Set a real
TERRA_KEK. Without it the stores are sealed underTERRA_TOKEN, so rotating the API token re-keys the credential store — and for operator secrets, which have no seed to recover from, it makes them permanently undecryptable.
Egress
| Variable | Default | Purpose |
|---|---|---|
TERRA_WARDEN_PORT |
8888 |
Loopback port the worker proxies through. |
TERRA_GATEWAY_ALLOW |
— | Comma-separated allow-list seed for the initial policy (console-managed thereafter). |
TERRA_AUDIT_DRAIN_S |
10 |
How often each live session’s Warden audit is mirrored onto the orchestrator’s volume. Also bounds how stale the console’s egress feed can be. 0 disables the sweep (stop/detach still drain). |
WARDEN_CA_CN / WARDEN_CA_ORG / WARDEN_CA_C |
Zscaler Root CA / Zscaler Inc. / US |
Identity the interception CA presents to the agent — a believable enterprise proxy rather than a Terrarium fingerprint. |
Budgets and backstops
Three independent bounds, because the first is worker-reported and therefore forgeable:
| Variable | Default | Purpose |
|---|---|---|
TERRA_BUDGET_HARD_MULT |
1.25 |
Hard-kill once cumulative cost exceeds max_budget_usd × this. |
TERRA_BUDGET_MAX_TURNS |
1000 |
Orchestrator-counted result events before a hard kill. Unforgeable. 0 disables. |
TERRA_BUDGET_MAX_RUN_SECONDS |
7200 |
Hard-kill a turn that runs this long without ever finishing (no result). Catches an agent that streams forever. 0 disables. |
Limits
| Variable | Default | Purpose |
|---|---|---|
TERRA_MAX_LIVE_SESSIONS |
32 |
Global admission cap. |
TERRA_MAX_LIVE_SESSIONS_PER_AGENT |
4 |
Per-agent admission cap. |
TERRA_MAX_EVENT_LOG_BYTES |
256 MiB |
Per-session event log cap. Crossing it terminates the producer rather than truncating evidence. |
TERRA_MAX_AUDIT_LOG_BYTES |
256 MiB |
Same, for the egress audit. |
TERRA_MEMORY_SNAPSHOT_MAX_BYTES |
— | Cap on a synced memory snapshot. |
TERRA_K8S_MEMORY_SIZE |
1Gi |
Per-agent memory PVC size. |
TERRA_K8S_WORKSPACE_SIZE |
2Gi |
Per-session workspace size. |
TERRA_K8S_MEMORY_EMPTYDIR_SIZE |
256Mi |
synced-mode scratch. |
TERRA_K8S_AUDIT_SIZE |
256Mi |
Warden’s in-Pod audit emptyDir. |
Kubernetes
| Variable | Default | Purpose |
|---|---|---|
TERRA_K8S_NAMESPACE |
from the service-account mount | Namespace sandbox Pods are created in. |
TERRA_K8S_STORAGE_CLASS |
cluster default | Storage class for memory/workspace PVCs. |
Notifications
| Variable | Default | Purpose |
|---|---|---|
TERRA_NOTIFY_WEBHOOK |
— | Fire-and-forget webhook (Discord/Slack/ntfy/…). |
TERRA_NOTIFY_ON |
session_end,error,budget_exceeded |
Comma-separated event types to notify on. |
Memory
memory_mode is a per-agent harness setting, not an environment variable, and it is the
biggest lever on Kubernetes launch latency:
| Mode | Behaviour |
|---|---|
volume |
Mount the per-agent RWO PVC at /memory. Survives anything; costs ~11s of volume attach per launch on Kubernetes. |
synced (default) |
No mount. The orchestrator restores a snapshot before the agent runs and snapshots back at each turn end. Fast launch; writes since the last turn are lost if the sandbox dies abruptly. |
none |
No mount, no snapshot. /memory is container-local scratch. Correct for agents that never take notes. |
Under Docker a local volume attaches in ~0ms, so synced and volume behave identically —
the console says so rather than quoting a Kubernetes number at you.
Per-agent CLI knobs
An agent’s harness env is merged into the sandboxed CLI’s environment, so any Claude Code
environment variable can be set per agent.
The one worth knowing for budgeting: since CLI 2.1.219 a subagent may spawn nested
subagents to depth 3 (previously 1), which multiplies the fan-out a single turn can
produce. The backstops above still bound a runaway, but they bound it later. Set
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1 in an agent’s env to restore flat delegation for
cost-sensitive agents.
Warden (set per session by the orchestrator)
Listed for reading logs and debugging, not for you to configure:
WARDEN_LISTEN, WARDEN_POLICY, WARDEN_CRED, WARDEN_SECRETS, WARDEN_CA_DIR,
WARDEN_AUDIT, WARDEN_RECEIPT_KEY, WARDEN_ALLOW, WARDEN_INJECT, WARDEN_MAX_CONNS,
WARDEN_STREAM_IDLE_SECS.