Environment Variables
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.
License and core secrets
Section titled “License and core secrets”| Variable | Required | Default / example | Description |
|---|---|---|---|
BRUTOR_LICENSE_KEY |
Yes | BRUTOR-V1-... |
License key. The Core Proxy refuses to start without it. |
JWT_SECRET |
Yes | openssl rand -hex 32 |
HS256 signing secret for gateway/portal JWTs. Shared Core Proxy + Control Plane. |
ENCRYPTION_KEY |
Yes | python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" |
Fernet key encrypting stored secrets. Shared across both planes. |
QDRANT_JWT_SIGNING_SECRET |
Yes | openssl rand -hex 32 |
Signs the short-lived tenant-scoped Qdrant JWTs. Shared Core Proxy ↔ Qdrant. |
SKILL_RUNNER_JWT_SECRET |
Yes | openssl rand -hex 32 |
Authenticates Core Proxy → Skill Runner calls. Must match on both services. |
PROXY_HEALTH_CHECK_API_KEY |
Yes | sk_brutor_api_<43 url-safe chars> |
API key used by internal health checks against the proxy. |
SYSTEM_ADMIN_PASSWORD |
Yes | Admin123! |
Seeded system-admin password. Change in production. |
DEFAULT_TENANT_ADMIN_PASSWORD |
Yes | Admin123! |
Seeded tenant-admin password. Change in production. |
BRUTOR_VERSION |
Yes (compose) | 0.9.67 |
Image tag for all Brutor services in the compose file. |
Database (PostgreSQL — shared by both planes)
Section titled “Database (PostgreSQL — shared by both planes)”| Variable | Required | Default / example | Description |
|---|---|---|---|
DB_HOST |
Yes | postgres |
Database host |
DB_PORT |
No | 5432 |
Database port (also the host-mapped port) |
DB_USER |
Yes | brutor |
Database user |
DB_PASSWORD |
Yes | brutor123 |
Database password |
DB_NAME |
Yes | ai_gateway |
Database name |
DB_POOL_SIZE |
No | 20 |
Connection pool size |
DATABASE_URL |
Yes (native runs) | postgresql://brutor:brutor123@localhost:5432/ai_gateway |
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.
| Variable | Required | Default / example | Description |
|---|---|---|---|
REDIS_URL |
Yes | redis://redis:6379/0 |
Cache, rate-limit counters, pub/sub |
REDIS_DISABLED |
No | false |
true = in-memory fallback — single-pod only |
REDIS_PORT |
No | 6379 |
Host-mapped Redis port (compose) |
Ports (compose host mappings)
Section titled “Ports (compose host mappings)”| Variable | Required | Default | Description |
|---|---|---|---|
PROXY_PORT |
No | 8100 |
Core Proxy (runtime + Portal API) |
GATEWAY_PORT |
No | 5050 |
Control Plane (admin API) |
ADMIN_UI_PORT |
No | 3002 |
Admin Console |
PORTAL_PORT |
No | 3001 |
User Portal |
QDRANT_REST_PORT |
No | 6333 |
Qdrant REST |
QDRANT_GRPC_PORT |
No | 6334 |
Qdrant gRPC |
MINIO_API_PORT |
No | 9000 |
MinIO S3 API |
MINIO_CONSOLE_PORT |
No | 9001 |
MinIO console |
Auth and CORS
Section titled “Auth and CORS”| Variable | Required | Default / example | Description |
|---|---|---|---|
JWT_EXPIRES_IN |
No | 3600 |
JWT lifetime in seconds |
JWT_ALGORITHM |
No | HS256 |
JWT signing algorithm |
CORS_ALLOW_ALL |
No | false |
Allow all origins (dev only) |
CORS_ORIGINS |
No | http://localhost:3001,http://localhost:3002 |
Comma-separated allowed origins |
Semantic cache
Section titled “Semantic cache”| Variable | Required | Default / example | Description |
|---|---|---|---|
SEMANTIC_CACHE_ENABLED |
No | true |
Enable the LLM semantic cache |
MCP_STATELESS_ENABLED |
No | false |
Serve the stateless MCP 2026-07-28 dialect (server/discover, per-request _meta) from the gateway’s synthesized servers and probe upstreams stateless-first. Legacy handshake clients/servers work regardless. |
EMBEDDING_MODEL |
No | text-embedding-3-small |
Model used to embed prompts for similarity lookup |
SIMILARITY_THRESHOLD |
No | 0.95 |
Minimum cosine similarity for a semantic hit |
SEMANTIC_CACHE_EXACT_TTL_SECS |
No | 3600 |
Exact-match entry TTL |
SEMANTIC_CACHE_SEMANTIC_TTL_SECS |
No | 86400 |
Semantic-match entry TTL |
SEMANTIC_CACHE_TIME_BUCKET |
No | daily |
Time-bucketing for cache keys |
Knowledgebase (KB uploader)
Section titled “Knowledgebase (KB uploader)”| Variable | Required | Default / example | Description |
|---|---|---|---|
DEFAULT_EMBEDDING_MODEL |
No | text-embedding-3-small |
Default embedding model for KB collections |
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 |
Media storage (images / audio / video)
Section titled “Media storage (images / audio / video)”| Variable | Required | Default / example | Description |
|---|---|---|---|
MEDIA_STORAGE_BACKEND |
No | s3 |
Storage backend |
MEDIA_BUCKET |
No | brutor-media |
Bucket name |
MEDIA_S3_ENDPOINT |
No | http://minio:9000 |
S3 endpoint (MinIO in the bundle) |
MEDIA_S3_ACCESS_KEY_ID |
Yes (s3) | minioadmin |
S3 access key |
MEDIA_S3_SECRET_ACCESS_KEY |
Yes (s3) | minioadmin |
S3 secret key |
MEDIA_S3_FORCE_PATH_STYLE |
No | true |
Path-style addressing (required for MinIO) |
MEDIA_SIGNED_URL_TTL_SECS |
No | 900 |
Signed URL lifetime |
MEDIA_GC_INTERVAL_SECS |
No | 21600 |
Expired-media garbage-collection interval |
Skill Runner
Section titled “Skill Runner”| Variable | Required | Default / example | Description |
|---|---|---|---|
SKILL_RUNNER_URL |
No | http://skill-runner:8210 |
Internal Skill Runner address (Core Proxy side) |
SKILL_RUNNER_JWT_SECRET |
Yes | openssl rand -hex 32 |
Shared Core Proxy ↔ Skill Runner |
SKILL_RUNNER_JWT_TTL_SECS |
No | 300 |
Per-call JWT lifetime |
SANDBOX_TIMEOUT_SECS |
No | 30 |
Sandboxed execution timeout |
TRUSTED_TIMEOUT_SECS |
No | 120 |
Trusted execution timeout |
MAX_REQUEST_BYTES |
No | 16777216 |
Max request size to the runner (16 MB) |
Key management (KMS)
Section titled “Key management (KMS)”| Variable | Required | Default / example | Description |
|---|---|---|---|
KEY_PROVIDER |
No | local |
local | aws_kms | vault |
KMS_KEY_ID |
If aws_kms |
arn:aws:kms:... |
AWS KMS key |
AWS_REGION |
If aws_kms |
eu-west-1 |
AWS region |
AWS_KMS_ENDPOINT_URL |
No | http://localstack:4566 |
Override for LocalStack (compose kms profile) |
VAULT_ADDR |
If vault |
http://vault:8200 |
Vault address |
VAULT_TOKEN |
If vault |
... |
Vault token |
VAULT_TRANSIT_KEY |
If vault |
brutor |
Transit key name |
VAULT_TRANSIT_MOUNT |
If vault |
transit |
Transit mount path |
Logging
Section titled “Logging”| Variable | Required | Default / example | Description |
|---|---|---|---|
LOG_LEVEL |
No | info |
Control Plane log level |
USE_JSON_LOGGING |
No | true |
Structured JSON logs (Control Plane) |
RUST_LOG |
No | brutor_gateway_core=info,tower_http=info |
Core Proxy log filter |
Deployment mode
Section titled “Deployment mode”| Variable | Required | Default / example | Description |
|---|---|---|---|
BRUTOR_DEPLOYMENT_MODE |
No | self_hosted |
self_hosted | saas | development |
MCP_DEPLOYMENT_DRIVER |
No | docker |
Driver for gateway-deployed MCP servers: docker | k8s | ecs | none |
BRUTOR_SHARED_MCP_SERVERS |
No | [{...}] |
JSON array of MCP servers auto-registered at startup |
Frontend (Vite build-time)
Section titled “Frontend (Vite build-time)”| Variable | Required | Default / example | Description |
|---|---|---|---|
VITE_GATEWAY_URL (Admin UI) |
Yes | http://localhost:5050 |
Admin UI → Control Plane |
VITE_GATEWAY_URL (Portal) |
Yes | http://localhost:8100 |
User Portal → Core Proxy (the portal never talks to the Control Plane) |
VITE_TENANT_ID (Portal) |
Yes | default |
Tenant the portal serves |
