Skip to main content
Version: 0.10.0

Configuration Reference

All DecisionBox services are configured via environment variables. This page lists every variable, its default, and which service uses it.

Agent

The agent (decisionbox-agent) is a standalone binary that runs discovery. It reads project configuration from MongoDB but needs environment variables for infrastructure access.

Required

VariableDefaultDescription
MONGODB_URI(required)MongoDB connection string. Examples: mongodb://localhost:27017, mongodb+srv://user:pass@cluster.mongodb.net
MONGODB_DBdecisionboxMongoDB database name. Must match the API's database.

Secret Provider

The agent reads LLM API keys and warehouse credentials from a secret provider. These are configured per-project via the dashboard.

VariableDefaultDescription
SECRET_PROVIDERmongodbWhich secret provider to use. Options: mongodb, gcp, aws, azure
SECRET_NAMESPACEdecisionboxNamespace prefix for all secrets. Prevents conflicts in shared cloud accounts.
SECRET_ENCRYPTION_KEY(empty)Base64-encoded 32-byte AES key for MongoDB secret provider. Generate with: openssl rand -base64 32. If empty, secrets are stored in plaintext (with warning).
SECRET_GCP_PROJECT_ID(empty)GCP project ID. Only required when SECRET_PROVIDER=gcp.
SECRET_AWS_REGIONus-east-1AWS region. Only used when SECRET_PROVIDER=aws.
SECRET_AZURE_VAULT_URL(empty)Azure Key Vault URL (e.g., https://my-vault.vault.azure.net/). Only required when SECRET_PROVIDER=azure.

LLM Behavior

VariableDefaultDescription
LLM_MAX_RETRIES3Number of retries on LLM API errors (rate limits, timeouts). Set to 0 for no retries.
LLM_TIMEOUT300sHTTP timeout per LLM API call. Go duration format: 30s, 2m, 5m. Read by the agent at startup and threaded through to every provider as cfg["timeout_seconds"]. Per-project timeout_seconds in the LLM config (dashboard) overrides this when set. Invalid or zero values fall back to the 300s default. The API process reads the same env var but with no default — when unset, each provider keeps its own hard-coded fallback (60s for Claude direct API, 5m for OpenAI/Bedrock/Vertex/Azure Foundry, 15m for Ollama (reasoning-on local generations want a longer window)); see the API Configuration section below.
LLM_REQUEST_DELAY_MS1000Delay between consecutive LLM calls in milliseconds. Helps with rate limiting and cost control. Set to 0 for no delay.

Discovery Run Budget

VariableDefaultDescription
DISCOVERY_MAX_DURATION24hIn-agent ctx cap on a single discovery run. Go duration format: 2h, 24h, 168h. Acts as a runaway-loop safety net — per-step budgets (warehouse QueryTimeout, LLM_TIMEOUT + LLM_RETRY_*, per-table schema timeout) are what keep stuck operations responsive within a run. Set to 0 to disable the in-agent cap entirely for installs that prefer to rely solely on per-step budgets (typical for very large warehouses with multi-hour SQL scans). Invalid or negative values log a warning and fall back to 24h. The tail-end persistence step (Mongo writes, embed/index, status update) always runs under its own 10-minute budget regardless of this setting, so a completed run is never lost to a deadline. Must coexist with AGENT_JOB_TIMEOUT_HOURS on the API side: the API's K8s Job ActiveDeadlineSeconds and the subprocess watcher are driven by AGENT_JOB_TIMEOUT_HOURS, so the agent is killed outright at that wall-clock cap regardless of DISCOVERY_MAX_DURATION. Keep DISCOVERY_MAX_DURATION < AGENT_JOB_TIMEOUT_HOURS so the in-agent cap fires first and the agent saves partial results gracefully. For multi-hour SQL, raise both consistently (e.g. AGENT_JOB_TIMEOUT_HOURS=25 + DISCOVERY_MAX_DURATION=24h).

Validation

The LLM-native verifier + refuter run in Phase 4.5 (insights) and Phase 5.5 (recommendations) of every discovery. See Insight validation for the architectural overview.

VariableDefaultDescription
VALIDATION_REFUTER_ENABLEDtrueWhen false, only the verifier runs. The refuter side carries no weight in Combine() and every doc is stamped refuter_disabled: true. Useful when refuter telemetry shows ≤5% rejection rate and the cost isn't pulling its weight.
VALIDATION_MAX_INSIGHTS_PER_RUN30Run-level cap on validated insights. Insights are ordered by affected_count descending; surplus get combined = "skipped_budget_cap".
VALIDATION_MAX_RECOMMENDATIONS_PER_RUN15Run-level cap on validated recommendations.
VALIDATION_VERIFIER_MAX_ROUNDS8Max LLM rounds per verifier run before forced-final.
VALIDATION_VERIFIER_TOKEN_CAP30000Soft cap on cumulative tokens (input + output) per verifier run. When exceeded, the loop bails to forced-final.
VALIDATION_VERIFIER_MAX_OUTPUT4000Per-call max output tokens for the verifier.
VALIDATION_REFUTER_MAX_ROUNDS6Same as the verifier knob, refuter side.
VALIDATION_REFUTER_TOKEN_CAP20000Soft token cap for the refuter.
VALIDATION_REFUTER_MAX_OUTPUT3000Per-call max output tokens for the refuter.
VALIDATION_BUNDLE_SAMPLE_ROWS50How many rows per source step the bundle samples for read_step_rows.
VALIDATION_BUNDLE_CELL_CHAR_CAP200Per-cell character cap on row values in the rendered bundle. Strings over the cap are truncated with an ellipsis.
VALIDATION_REC_STEPS_TOKEN_BUDGET12000Token budget for the union of source steps a recommendation bundle includes. Over-budget steps are omitted and source_steps_truncated: true is surfaced in the prompt.
VALIDATION_ESTIMATE_TOKEN_RATIO3.5Characters-to-token ratio used for the in-loop prompt-size estimate. Lower → more conservative budgeting.
VALIDATION_MAX_READ_STEP_ROWS200Per-call cap on the row count the read_step_rows tool returns. The agent may still ask for more; we silently clamp and the result carries truncated: true so the agent knows further rows are available.
VALIDATION_NUMERIC_TOLERANCE0.20Relative tolerance (±20% by default) for comparing a claim's quantitative figure against row evidence. Prevents rounding-noise rejections — e.g. a "27% spike" claim with evidence of 26.5% stays supported. Only applies to magnitude/figure components; ranking and superlative claims are exact-match.
VALIDATION_MIN_SAMPLE_SIZE30Minimum row population the refuter must observe before using a row as counter-evidence for a market-wide superlative claim. Below this, a contradicting outlier is dismissed (apples-to-apples — small-sample contradictions don't disprove the headline).

Vector Search (Qdrant)

The agent uses Qdrant to store and index embeddings during the discovery process.

VariableDefaultDescription
QDRANT_URL(empty)Qdrant gRPC endpoint (e.g., qdrant:6334). If empty, vector indexing is disabled.
QDRANT_API_KEY(empty)Optional API key for authenticated Qdrant instances.

Telemetry

VariableDefaultDescription
TELEMETRY_ENABLEDtrueEnable anonymous usage telemetry. Set to false to disable. See Telemetry for details.
DO_NOT_TRACK(empty)Set to 1 to disable telemetry. Follows the Console Do Not Track standard.
TELEMETRY_ENDPOINThttps://telemetry.decisionbox.io/v1/eventsTelemetry collection endpoint. Override for self-hosted collection.
TELEMETRY_FLUSH_INTERVAL5mHow often to send batched telemetry events. Go duration format: 30s, 5m, 1h.

Operational

VariableDefaultDescription
SERVICE_NAMEdecisionbox-agentService name that appears in log output.
ENVdevEnvironment. dev = human-readable console logs. prod or production = structured JSON logs.
LOG_LEVELinfoLog verbosity. Options: debug, info, warn, error.

Agent CLI Flags

The agent also accepts command-line flags (typically set by the API when spawning):

FlagRequiredDefaultDescription
--modeNo(empty)Alternate run mode: index-schema or validate-doc. Empty runs discovery (the default).
--project-idYesProject ID to run discovery for.
--run-idNoDiscovery run ID for live status updates. Set by the API.
--areasNo(all)Comma-separated analysis areas to run. Empty = all areas. Example: --areas churn,monetization
--max-stepsNo100Maximum exploration steps. More steps = more comprehensive but slower and more expensive.
--min-stepsNo0Minimum exploration steps before the agent accepts a done signal from the LLM. Early done signals are rejected (recorded as complete_rejected) and exploration continues. 0 disables the floor. Use on reasoning models (Qwen3, DeepSeek-R1, GPT-OSS) that terminate too early.
--estimateNofalseEstimate cost only (no actual discovery). Outputs JSON to stdout.
--skip-cacheNofalseForce re-discovery of warehouse schemas (ignore cache).
--enable-debug-logsNotrueWrite detailed debug logs to MongoDB (TTL: 30 days).
--testNofalseTest mode — limits analysis for faster runs.
--test-connectionNo(empty)Test a provider connection and exit. One of warehouse, llm, embedding, blurb-llm.
--job-idNo(empty)ValidationJob _id when --mode=validate-doc. Ignored in other modes.

API

The API (decisionbox-api) is the REST server that manages projects, discoveries, and spawns agents.

Required

VariableDefaultDescription
MONGODB_URI(required)MongoDB connection string. Must be the same database as the agent.
MONGODB_DBdecisionboxMongoDB database name.
PORT8080HTTP listen port.

Secret Provider

Same variables as the agent — the API reads secrets to display masked values in the dashboard.

VariableDefaultDescription
SECRET_PROVIDERmongodbSame as agent. Must match.
SECRET_NAMESPACEdecisionboxSame as agent. Must match.
SECRET_ENCRYPTION_KEY(empty)Same as agent. Must match.
SECRET_GCP_PROJECT_ID(empty)Same as agent.
SECRET_AWS_REGIONus-east-1Same as agent.
SECRET_AZURE_VAULT_URL(empty)Same as agent.

Vector Search (Qdrant)

The API uses Qdrant to perform semantic searches and retrieval of indexed data.

VariableDefaultDescription
QDRANT_URL(empty)Qdrant gRPC endpoint (e.g., qdrant:6334). If empty, vector search is disabled.
QDRANT_API_KEY(empty)Optional API key.

LLM Behavior

The API talks to LLMs for /ask. Per-project LLM credentials and timeout_seconds are read from the project's LLM config (set in the dashboard); these env vars are deployment-wide defaults.

VariableDefaultDescription
LLM_TIMEOUT(provider-specific)HTTP timeout per LLM API call, applied to every registered provider. Go duration format: 30s, 2m, 15m. Per-project timeout_seconds overrides this when set. When unset, providers use their hard-coded default (60s for Claude direct API, 5m for OpenAI/Bedrock/Vertex/Azure Foundry, 15m for Ollama (reasoning-on local generations want a longer window)). Raise this when long-form generations (e.g. executive summaries on Opus-class models) exceed 5 minutes. Same env var the agent reads — set it once on both containers.

No env vars are needed for /ask context budgeting. The handler reads each model's published context window from its catalog entry (MaxInputTokens) and sizes the prompt against it automatically. Models with no declared window fall back to a conservative 32K. See Ask: Token-Aware Context Budgeting for the full algorithm and the typed error codes the dashboard branches on.

Agent Runner

The API spawns the agent for each discovery run. Two modes:

VariableDefaultDescription
RUNNER_MODEsubprocessHow to spawn the agent. subprocess = exec.Command (local dev, agent binary must be in PATH). kubernetes = create a K8s Job per discovery (production).

Subprocess mode — No additional configuration. The agent binary (decisionbox-agent) must be in the system PATH.

Kubernetes mode — Additional configuration:

VariableDefaultDescription
AGENT_IMAGEghcr.io/decisionbox-io/decisionbox-agent:latestDocker image for the agent container.
AGENT_NAMESPACEdefaultKubernetes namespace for agent Jobs.
AGENT_SERVICE_ACCOUNT""Kubernetes service account for agent Jobs. Set to the agent SA with Workload Identity for GCP Secret Manager / BigQuery access.
AGENT_CPU_REQUEST250mCPU request for agent containers (K8s resource quantity).
AGENT_CPU_LIMIT2CPU limit for agent containers.
AGENT_MEMORY_REQUEST256MiMemory request for agent containers.
AGENT_MEMORY_LIMIT1GiMemory limit for agent containers.
AGENT_JOB_TIMEOUT_HOURS25Wall-clock budget for one agent run. Used as the K8s Job's ActiveDeadlineSeconds (hard kill at the cap) and as the subprocess watcher timeout — applies in both runner modes. The default is paired with the agent's 24h DISCOVERY_MAX_DURATION default so the in-agent cap fires first (with 1h headroom for the agent's 10-minute persistence tail + clock skew) and the agent fails gracefully rather than being killed mid-write. If you change DISCOVERY_MAX_DURATION you must keep this value at least 1h above it; a startup WARN log fires when they are inconsistent.

Telemetry

Same variables as the agent — see the Agent Telemetry section above.

Operational

VariableDefaultDescription
SERVICE_NAMEdecisionbox-apiService name in logs.
ENVdevEnvironment (dev or prod).
LOG_LEVELinfoLog level: debug, info, warn, error.

Dashboard

The dashboard (decisionbox-dashboard) is a Next.js application that proxies API requests via middleware.

VariableDefaultDescription
API_URLhttp://localhost:8080Backend API URL. Server-side only — not exposed to the browser. In Docker: http://api:8080. In K8s: http://decisionbox-api:8080.
PORT3000Dashboard listen port.
HOSTNAME0.0.0.0Bind address. 0.0.0.0 = all interfaces. 127.0.0.1 = localhost only.

Important: API_URL is a runtime variable read by Next.js middleware on each request. It is NOT baked at build time. This means a single Docker image works across all environments — just change the environment variable.


Docker Compose

The docker-compose.yml includes all variables with documentation. Here's the minimal configuration:

services:
mongodb:
image: mongo:7.0
ports: ["27017:27017"]
volumes: [mongodb_data:/data/db]

api:
build: { context: ., dockerfile: services/api/Dockerfile }
ports: ["8080:8080"]
environment:
- MONGODB_URI=mongodb://mongodb:27017
- MONGODB_DB=decisionbox
- SECRET_PROVIDER=mongodb
- SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY:-}
- RUNNER_MODE=subprocess
depends_on:
mongodb: { condition: service_healthy }

dashboard:
build: { context: ui/dashboard, dockerfile: Dockerfile }
ports: ["3000:3000"]
environment:
- API_URL=http://api:8080
depends_on: [api]

volumes:
mongodb_data:

Generating an Encryption Key

For the MongoDB secret provider, generate a 32-byte encryption key:

# Generate key
openssl rand -base64 32

# Set in docker-compose or .env file
export SECRET_ENCRYPTION_KEY=$(openssl rand -base64 32)
docker compose up -d

File-Based Secrets (Kubernetes)

Environment variables support a file:// prefix for Kubernetes secret mounts:

# In K8s, mount secrets as files and reference them:
SECRET_ENCRYPTION_KEY=file:///var/run/secrets/encryption-key

This reads the file contents instead of using the env var value directly.


Precedence

  1. Environment variables — Highest priority. Override everything.
  2. Defaults in code — Used when env var is not set.
  3. Project configuration (MongoDB) — Per-project settings (warehouse, LLM, schedule) are stored in MongoDB and configured via the dashboard.

Analysis Phase Compaction Tunables

Bounded analysis prompts via vector-ranked step selection + per-step compact digest. Algorithm parameters live in code, not env vars — edit and redeploy to change. See agent-analysis-compaction.md for the full design.

ConstantDefaultWhat it controls
models.CompactInlineThreshold20Row-count cap below which the digest stores every row verbatim (AllRows). Above the cap, only head + tail.
models.TopValueCardinality20Distinct-value cap above which a string column emits no Top list — guards against PII (user IDs / free text).
models.HeadTailRowCount5Rows in HeadRows and TailRows (the boundary samples for results above the inline threshold).
discovery.AnalysisAreaTopK24Maximum vector hits per area before exact-match boost + budget trim.
discovery.AnalysisAreaMinScore0.30Cosine-similarity floor; vector hits below it are dropped (recorded as below_min_score in telemetry).
discovery.ExactMatchFloor0.55Score assigned to steps promoted via the keyword exact-match boost — set above the min-score floor.
discovery.AnalysisQueryResultsBudgetTokens200_000Soft cap on the rendered {{QUERY_RESULTS}} block, in tokens. Picker drops lowest-scored steps until under cap.

When to tune:

  • CompactInlineThreshold — Lower (10) if your domain produces many 20-50 row aggregates and the head+tail summary loses too much detail.
  • AnalysisAreaTopK — Lower if you regularly hit budget trimming; higher if the picker is clearly missing relevant steps.
  • AnalysisAreaMinScore — Lower (0.20) for highly-multilingual runs where cosine similarity is naturally smaller across languages.
  • AnalysisQueryResultsBudgetTokens — Lower if the surrounding prompt grows; raise only on models with substantially-larger context windows.

Next Steps