Reference for every environment variable used by the trial bundle and self-hosted deployments (brutor-trial-service/trial_bundle/.env). Setup walkthrough: Docker Compose install and Configuration.
Image tag for all Brutor services in the compose file. Deliberately not pinned to a literal here: a stale example gets copy-pasted into a .env, and an image tag that predates the current schema will not serve a database the Control Plane has already migrated.
Full connection URL when running the planes outside compose
The Control Plane owns the schema and runs Alembic migrations automatically on startup (with an advisory lock, so concurrent instances don’t race). The Core Proxy never alters the schema — upgrades are pull-new-images-and-restart.
Comma-separated tenant ids a global-scope API key may act for when it sends X-Tenant-ID for a tenant other than its own. Unset means a global key is always attributed to its owning tenant.
Tenant admins configure URLs the Core Proxy and the KB connector runtime then
fetch with their own network position: MCP servers, LLM endpoints, A2A agents,
IdP discovery, connector sources. The policy is applied three times with one
rule set — when a URL is saved (Control Plane, HTTP 400 with the reason),
and when it is fetched (Core Proxy and connector sync, after DNS
resolution, so a public name that resolves to a private address is refused
too). Link-local addresses (169.254/16, fe80::/10 — where every cloud
metadata service lives), the IPv6 metadata address and reserved addresses are
always refused. Set both variables on the Core Proxy, the Control Plane and
the KB connector sync service.
Variable
Required
Default / example
Description
BRUTOR_OUTBOUND_DENY_PRIVATE
No
false
Also refuse loopback, RFC 1918, carrier-grade NAT (100.64/10) and IPv6 unique-local destinations. Turn on for multi-tenant deployments. Off by default so a self-hosted stack that runs Ollama or an MCP server next to the proxy keeps working.
BRUTOR_OUTBOUND_ALLOW_HOSTS
No
ollama,skill-runner,*.svc.cluster.local
Comma-separated hostnames that bypass the address checks. *.suffix matches a domain. List your own internal services here when BRUTOR_OUTBOUND_DENY_PRIVATE is on.
Deployment fallback judge model for semantic policies. Used only when the policy pins no judge and the tenant has no default. With none of the three set, the policy has no judge and fails open.
Model a newly-provisioned tenant gets as default_judge_model_id. Override in Settings → Tenant → Default models.
KB_POLL_INTERVAL_SECS
No
5
Job-queue poll interval
KB_MAX_CONCURRENT_JOBS
No
4
Concurrent ingestion jobs
KB_CHUNK_SIZE_TOKENS
No
500
Chunk size
KB_CHUNK_OVERLAP_TOKENS
No
50
Chunk overlap
KB_EMBEDDING_BATCH_SIZE
No
50
Texts per embedding request
KB_EMBEDDING_CONCURRENCY
No
4
Parallel embedding requests
STALE_PROCESSING_SECS
No
1800
A document left in processing longer than this (the uploader died or was restarted mid-batch) is claimed again instead of staying stuck until an operator reprocesses it. Set on the uploader container.
MAX_DOCUMENT_BYTES
No
52428800 (50 MiB)
Largest raw document the uploader reads into memory; larger rows are marked failed with a clear message. Office parts (.docx/.pptx XML) are additionally refused above 64 MiB inflated, which stops zip bombs. Set on the uploader container.
PROXY_SERVICE_API_KEY
Yes
(the PROXY_HEALTH_CHECK_API_KEY value)
Global-scope key the uploader uses to embed through the Core Proxy. The same key gates the uploader’s /api/v1/jobs listing API (X-API-Key or Authorization: Bearer); when unset that API answers 503.
KB_CONNECTOR_SYNC_MAX_RUN_SECS
No
3600
Connector run lease. A connector still marked running whose last_run_started_at is older than this is treated as abandoned and claimed again.
KB_CONNECTOR_SYNC_SHUTDOWN_GRACE_SECS
No
30
On SIGTERM the connector scheduler stops claiming and waits this long for in-flight syncs; anything still running is aborted and rescheduled for immediate retry.
Per-call JWT lifetime. Set on the Core Proxy, which mints the token
SKILL_RUNNER_JWT_LEEWAY_SECS
No
30
Clock skew the runner tolerates when validating that token
SKILL_RUNNER_SANDBOX_TIMEOUT_SECS
No
30
Sandboxed execution timeout
SKILL_RUNNER_TRUSTED_TIMEOUT_SECS
No
120
Trusted execution timeout
SKILL_RUNNER_MAX_REQUEST_BYTES
No
16777216
Max request size to the runner (16 MB)
SKILL_RUNNER_WORKSPACE_ROOT
No
system temp dir
Where per-run skill workspaces are created
SKILL_RUNNER_WORKSPACE_TTL_SECS
No
3600
How long a workspace survives before it is reaped
SKILL_RUNNER_LISTEN_ADDR
No
0.0.0.0:8210
Runner bind address
SKILL_RUNNER_TRUSTED_ENV_ALLOWLIST
No
(empty)
Comma-separated env vars a trusted skill may read
The three timeout/size variables carry the SKILL_RUNNER_ prefix in the
code (brutor-skill-runner/src/config.rs) and in the shipped compose file.
They were previously documented here without it, so an operator who set
SANDBOX_TIMEOUT_SECS=300 to lengthen a slow skill got no effect and no
warning — the runner kept the 30-second default and killed the skill.
Audit rows are always hash-chained, which detects modification. A signing key
additionally lets the proxy attest to each batch, which is what detects a wholesale
rewrite. Without one, System → Audit Chains reports unattested rather than
verified — an honest result, not a broken one.
Variable
Required
Default / example
Description
BRUTOR_AUDIT_SIGNING_KEY
No
openssl rand -hex 32
Ed25519 seed (32 bytes, hex) the Core Proxy signs audit checkpoints with. Unset = chained but unattested.
BRUTOR_AUDIT_TRUSTED_KEYS
No
<hex>,<hex>
Public keys whose signatures are still accepted, comma-separated. The current key is trusted implicitly; this is only needed for rotation.
Rotation is additive, so no migration and no re-signing:
Append the old public key to BRUTOR_AUDIT_TRUSTED_KEYS.
Set BRUTOR_AUDIT_SIGNING_KEY to the new seed and restart.
New batches are signed with the new key; everything the old key signed keeps
verifying, because its public half is stored on the checkpoint and still trusted.
Never remove a public key that signed checkpoints you still retain. Doing so reports
that history as forged — which is the alarm you want if the key really was
compromised, and a false one if it was merely retired.
Level enforced when the governance database is unreachable and no recent level is cached. restricted keeps reads and completions serving while refusing anything that changes the world. Set suspended for a total stop.
The proxy never falls back to autonomous. An operator who suspends a runaway agent
must not have that suspension undone by an unrelated database blip — which is exactly
the moment the control is being relied on.
Service-provider keypair for SAML SSO and the post-login path
A2A_SAMPLE_PUBLIC_URL
(see code)
Public URL stamped on the seeded sample agent card
APP_VERSION
dev
Reported by /v1/version; set by the release build
BRUTOR_GITHUB_TOKEN / GITHUB_TOKEN
(unset)
GitHub token used by the skill-source sync scheduler when it walks a skills repository (Agent Skills → Sources). Optional: without it the unauthenticated 60 requests/hour budget is too small for a full walk of a large repo such as Anthropic’s skills, and that source is skipped with a warning. A fine-grained personal access token with Contents: read-only on the target repositories lifts the limit to 5,000/hour
Both consoles ship a PostHog client that is off unless POSTHOG_KEY is set
(POSTHOG_HOST defaults to https://eu.i.posthog.com). When enabled, the
consoles identify the signed-in user with their id, email and tenant id
and send page/feature events to that host. Treat enabling it as a
data-processing decision for your deployment; there is no in-product opt-out.