Documentation
¶
Overview ¶
Command executor runs the platform-managed sandbox worker: it claims tool_exec work from the shared Postgres queue, runs the built-in toolset inside per-session Docker containers, and appends the agent.tool_result events the brain resumes on. It also claims the kinds that need no sandbox at all — web_exec, outputs_harvest and mcp_exec — on both environment kinds, since those run in this process rather than in a session's hands. Disposable "hands" — run as many as needed; a container dying is one tool-call error, not a lost session. Configuration is environment-driven:
DATABASE_URL Postgres DSN (required; same database as the
controlplane and brain). A pool_max_conns below 3
is refused: a provision and the reaper can pin a
session-lock connection each while their nested
queries still need the pool
EXECUTOR_IMAGE sandbox base image (default "debian:stable-slim")
EXECUTOR_WORKDIR working directory inside the sandbox (default
"/workspace")
EXECUTOR_LEASE_TTL work-item lease, Go duration (default "15m") —
must comfortably exceed a single tool's timeout
EXECUTOR_POLL_INTERVAL idle queue poll, Go duration (default "500ms")
EXECUTOR_STALL_TIMEOUT how long a claimed item may report no progress
before the lease keeper cancels it and lets the
lease lapse for another executor to reclaim (Go
duration, default "30m"). No off switch, and floored
at the longest single step this binary can name plus
a minute for the kill and the answer that follow it:
"11m" for one bash tool's timeout, or
EXECUTOR_REPO_CLONE_TIMEOUT plus a minute where that
is longer, since one clone is one silent interval.
The floor holds for the default too: a clone budget
the default cannot clear fails startup until this is
set. A budget under that step makes every reclaim
stall at the same place
EXECUTOR_REAP_INTERVAL sandbox reap pass interval, Go duration (default
"1m"); each pass destroys the sandboxes of
deleted (tombstone-evidenced), archived, and
terminated cloud sessions — self_hosted sandboxes
belong to the BYOC worker and are never touched
EXECUTOR_SANDBOX_IDLE_TTL idle sandbox lifetime, Go duration (default
"24h"; "0" disables the idle tier). An idle cloud
session older than this is checkpointed and its
sandbox reaped — unless it still owes work or an
unanswered confirmation ask. Requires object
storage; a blob-less executor disables the tier
at startup with one log line
EXECUTOR_CHECKPOINT_MAX_BYTES workspace-checkpoint size budget in bytes
(default 2147483648, 2 GiB); over budget the TTL
tier reaps without a checkpoint
EXECUTOR_REPO_CLONE_MAX_BYTES github_repository clone spool budget in
bytes (default 1073741824, 1 GiB), metered as the
clone's bytes land; over budget the clone is
abandoned and surfaces as a session.error
EXECUTOR_REPO_CLONE_TIMEOUT per-repository clone deadline (default 5m);
past it the clone is abandoned the same way
EXECUTOR_MCP_PASS_TIMEOUT budget for one mcp_exec pass (default 5m),
whether it is listing a session's MCP servers or
running a turn's calls; what it does not reach is
retried on the next pass rather than failing the run
CONTROLPLANE_URL where a session's egress gate fetches its config;
set with EXECUTOR_GATE_IMAGE to opt into the gate.
Unset: no gate runs; a gate-wanting session (limited
or vault-attached) falls back to the backend's own
fail-closed networking (Docker limited -> no egress),
while unrestricted sessions network directly as before
EXECUTOR_GATE_IMAGE the egress-gate container image (built with
`docker build --target gate`); opts into the gate
together with CONTROLPLANE_URL
SANDBOX_BACKEND "docker" (default) or "k8s"
DOCKER_HOST Docker daemon address for the docker backend
(falls back to the well-known socket)
SANDBOX_DOCKER_GATE_NETWORK Docker network a session's egress-gate
container joins (default "bridge")
SANDBOX_K8S_KUBECONFIG kubeconfig path for the k8s backend; empty, together
with an empty SANDBOX_K8S_CONTEXT, uses in-cluster
config, then the default loading rules
SANDBOX_K8S_CONTEXT kubeconfig context for the k8s backend
SANDBOX_K8S_NAMESPACE namespace for sandbox pods (default "default")
SANDBOX_K8S_NODE_SELECTOR node labels every sandbox pod requires, as
comma-separated key=value; empty places nothing.
Malformed fails startup
SANDBOX_K8S_TOLERATIONS taints every sandbox pod tolerates, as a JSON array
of Kubernetes Toleration objects; empty tolerates
nothing. Malformed fails startup
SANDBOX_K8S_IMAGE_PULL_SECRETS Secrets every sandbox pod pulls images
with, as comma-separated Secret names; empty adds
nothing. Malformed fails startup
SANDBOX_K8S_NETSETUP_IMAGE image carrying `ip` for the limited-networking
init container (default "busybox")
BLOB_BACKEND object storage: "s3" (default when empty) or
"gcs"; unset with no BLOB_ENDPOINT disables
skills materialization
BLOB_ENDPOINT S3-compatible object storage host:port, required
by the s3 backend
BLOB_ACCESS_KEY / BLOB_SECRET_KEY / BLOB_BUCKET / BLOB_REGION / BLOB_TLS /
BLOB_BUCKET_PRECREATED the rest of the storage config (as controlplane);
the gcs backend takes BLOB_BUCKET alone
SECRETS_BACKEND secrets cipher (docs/plan/12): "openbao", "local",
"gcpkms", or empty to run without one. The executor
decrypts one secret: a github_repository resource's
sealed token, per clone (docs/plan/25). Egress
substitution still decrypts controlplane-side, for
the per-session gate. Without a cipher, repository
mounts do not clone
BAO_ADDR / BAO_TOKEN / BAO_TRANSIT_KEY / SECRETS_MASTER_KEY / SECRETS_KEY_ID /
GCPKMS_KEY_NAME the rest of the cipher config (as controlplane)
TAVILY_API_KEY web_search backend key; unset leaves the tool
unconfigured (it answers is_error naming it)
JINA_API_KEY web_fetch backend key; web_fetch needs this OR
WEBFETCH_BASE_URL, else it answers is_error
WEBSEARCH_BASE_URL / WEBFETCH_BASE_URL Tavily-protocol / Jina-Reader-
protocol endpoints (default: the public ones)
WEBTOOL_ALLOWED_DOMAINS comma-separated operator allowlist for both web
tools (bare host, IPv4, or *.wildcard); empty =
unrestricted
OTEL_EXPORTER_OTLP_ENDPOINT optional OTLP/gRPC collector endpoint
OTEL_EXPORTER_OTLP_INSECURE "true" to export without TLS (default TLS)
Click to show internal directories.
Click to hide internal directories.