Every environment variable and configuration key the Engine reads, with the
default the code applies, what the value bounds, and where it applies. The
tables are generated by reading the source, not the deployment: when a
default is derived from the environment (the container's cgroup limit, the
cores the process may use) the derivation is stated, and the AKS column
gives the value the qualification cluster runs with, from the chart
(infra/helm/kaveon-engine, which since 2026-09-17 renders every memory and
exchange budget per role, so helm upgrade reproduces the StatefulSets that
were first changed with kubectl set env). "Not set" means the default
applies. Anything this page could not establish from the source is marked
as such rather than guessed. Checked against config.rs and main.rs on
2026-09-17: every variable the server reads is listed; the CLI's own
variables are in the last section.
Precedence: an environment variable overrides the matching key in the
configuration file (/etc/kaveon/config.toml, or the path given as the
first argument to kaveon-server). Sizes are bytes unless the unit column
says otherwise; there is no suffix parsing (3221225472, not 3 GiB).
Sources: engine/crates/server/src/config.rs (the server configuration),
engine/crates/exec/src/local_parallel.rs and partitioned.rs (operator
settings read at execution time), engine/crates/storage/src/adls_reader.rs
(scan lanes), engine/crates/server/src/transport.rs (IPC spool),
engine/crates/core/src/process_memory.rs (the process guard).
| Name | Config key | Default | Unit | What it bounds | Applies to | AKS qualification value |
|---|---|---|---|---|---|---|
KAVEON_QUERY_MEMORY_LIMIT_BYTES |
memory.query_limit_bytes |
536870912 (512 MiB); on a process with a memory limit, capped at the admission limit | bytes | One query memory pool: the statement on the coordinator, one task of the query on a worker. Every operator reservation answers to it. Must be greater than zero and at most the admission limit. | coordinator (per statement), worker (per task) | coordinator 536870912 (512 MiB), workers 3221225472 (3 GiB); chart values coordinator.memory.queryLimitBytes / workers.memory.queryLimitBytes |
KAVEON_MEMORY_ADMISSION_LIMIT_BYTES |
memory.admission_limit_bytes |
4294967296 (4 GiB) when the process is unlimited; on a limited process and neither the variable nor the key set: process limit minus the headroom (below) | bytes | The sum of admitted query pools on the node. A statement or task whose pool does not fit on arrival waits in the admission queue (next two rows). Cannot exceed the process limit. | coordinator, worker | coordinator 2147483648 (2 GiB), workers 4294967296 (4 GiB); chart values <role>.memory.admissionLimitBytes |
KAVEON_MEMORY_ADMISSION_QUEUE |
memory.admission_queue |
64 | statements (coordinator) or tasks (worker) | How many arrivals may wait for admission at once, in arrival order. The head of the queue is admitted first and only when its whole pool fits; nothing behind it is admitted ahead of it, and nothing arriving is admitted while anyone is queued. An arrival that finds the queue full is refused at once: HTTP 429 MEMORY_ADMISSION_REJECTED on the coordinator, a task failure the coordinator retries on a worker. 0 is the pre-2026-09-17 behaviour: whatever does not fit on arrival is refused on arrival. The default is the cap on open waiting requests, not on latency: the wait below bounds latency. |
coordinator, worker | not set (default 64; not yet measured on the cluster) |
KAVEON_MEMORY_ADMISSION_WAIT_SECONDS |
memory.admission_wait_seconds |
60 | seconds | How long a statement waits in the coordinator's admission queue before it is refused with HTTP 429 MEMORY_ADMISSION_REJECTED (the refusal carries admission_wait_ms; the statement stays in the history as FAILED with its wait). Must be positive when the queue is on. The ceiling of the per-request admission_wait_seconds. Workers do not apply it: a queued task waits until its query is cancelled or the coordinator's task timeout ends it. |
coordinator | not set (default 60) |
KAVEON_PROCESS_MEMORY_LIMIT_BYTES |
none | the container's cgroup limit (/sys/fs/cgroup/memory.max, then memory/memory.limit_in_bytes); max or the v1 unlimited sentinel means no limit; 0 disables the guard |
bytes | The process guard: reservations fail closed when live allocated bytes plus the request would leave less than the headroom under this limit. Headroom is max(15% of the limit, 256 MiB). |
coordinator, worker | not set: cgroup limits apply, 4 GiB on the coordinator and 6 GiB on the workers (chart resource limits) |
KAVEON_HASH_ADAPTIVE_BYTES |
none | min(query limit / 16, 64 MiB), then capped at query limit / 4 whatever is configured |
bytes | How much a hash aggregate or join may grow in memory before the adaptive partitioned operator starts spilling its partitions. Read per operator at execution time. | worker (task operators), coordinator (node-local operators) | not set |
KAVEON_ADAPTIVE_PARTIAL_AGGREGATION |
none | on |
on / off |
Whether a grouped partial aggregate judges its own reduction: after each flush round of at least 100 000 rows, a round that made a group for 0.8 or more of its rows switches the partial to passing rows through as their own partial rows (per-row states, the same encoding) for four rounds' worth, then eight, judging an aggregating round in between; a round that reduces resumes aggregating. off aggregates every row as before. The thresholds are constants (ADAPTIVE_PARTIAL_MIN_ROWS, ADAPTIVE_PARTIAL_THRESHOLD in partitioned.rs), justified there from the measured probe and encode costs. Read per operator at execution time; the task metrics report aggregate_partial_mode, aggregate_partial_passthrough_rows and aggregate_partial_reduction. |
worker (task partials), coordinator (node-local partials) | not set |
| Name | Config key | Default | Unit | What it bounds | Applies to | AKS qualification value |
|---|---|---|---|---|---|---|
KAVEON_LOCAL_PARALLELISM |
none | min(available cores, 4); whatever is set is then capped at 16 and at the available cores |
threads | Threads one task runs for a grouped partial aggregate, a DISTINCT, and the final merge; also the node-local aggregate on the coordinator. Rows are hash-partitioned by key across the threads so memory is one aggregator's. Must be a positive integer. | worker (per task), coordinator (node-local and final stages) | not set; the chart does not render it, so the default applies: 3 on a worker (CPU limit 3) and 2 on the coordinator (CPU limit 2). The 2026-09-11 Log row says the chart carried explicit values; the chart in this tree does not, so whether the live StatefulSets carry an explicit value is not established here. |
KAVEON_SCAN_PARALLELISM |
none | min(available cores, 4); 1 restores the single sequential decoder |
decoder lanes | Row-group decoder lanes per scan of a large ADLS object (adls_reader), and the worker threads of the reader's runtime. Values below 1 or unparsable fall back to the default. |
worker (scans), coordinator (node-local scans) | not set (default lanes: 3 on a worker) |
available cores is std::thread::available_parallelism(), which honours the
container's CPU quota on Linux.
| Name | Config key | Default | Unit | What it bounds | Applies to | AKS qualification value |
|---|---|---|---|---|---|---|
KAVEON_HASH_SPILL_MODE |
disk | unset or any other value: the spill paths behave as KAVEON_HASH_SPILL_ROOT describes |
memory, memory-only |
Chooses the adaptive in-memory partial aggregate instead of writing partitions to disk. It flushes bounded rounds and passes near-unique input straight through, so no binary state is written per row — faster where memory is ample, which is why qualification runs and single-node deployments use it. Disk spill stays the default because a constrained production node needs the bounded-memory guarantee more than the speed. Read before KAVEON_HASH_SPILL_ROOT, so a memory mode disables spill whether or not a root is set. |
worker, coordinator | unset (disk spill) |
KAVEON_HASH_SPILL_ROOT |
none | unset: memory-only execution, no spill | directory path | Where the partitioned hash aggregate, join, sort and TopN spill their partitions and runs. Setting it turns the spill paths on for every query on the node; it must not be empty. | worker, coordinator | /tmp/spill (chart, both roles) |
KAVEON_HASH_SPILL_BYTES |
none | 10737418240 (10 GiB) | bytes | One query's spill budget across all its spilling operators on this node (a SpillManager shared through the query pool). Not a process-wide quota. |
worker, coordinator | 4294967296 (4 GiB, chart spillDiskLimitBytes) |
KAVEON_HASH_SPILL_PARTITIONS |
none | 16 | partitions | Spill partition count per partitioned operator; 1 to 256. For a join it is the fan-out of every repartitioning level: a partition whose build is still refused is split this many ways again, to three levels (MAX_JOIN_SPILL_DEPTH), after which the join fails closed. |
worker, coordinator | not set |
KAVEON_SPILL_COMPRESSION |
none | unset: spill runs are written uncompressed | lz4 / lz4_frame / true / 1; any other value is off |
Compresses the Arrow IPC spill runs the hash aggregate, join, sort and TopN write, with LZ4 frame. Opt-in while it is qualified: it can cut the disk traffic of a high-cardinality grouped-state run, and it adds CPU to every batch written and read back, so it has to be measured against the uncompressed default rather than assumed. Read once when a spill writer is opened. | worker, coordinator | not set (uncompressed) |
| Name | Config key | Default | Unit | What it bounds | Applies to | AKS qualification value |
|---|---|---|---|---|---|---|
KAVEON_COORDINATOR_EXCHANGE_SPOOL |
none | true |
boolean (true/false) |
Whether the coordinator keeps a disk exchange store and acts as the hub for exchange partitions. Off, workers hold payloads in memory unless the worker spool is on. | coordinator | false (chart value coordinator.exchange.spool) |
KAVEON_WORKER_EXCHANGE_SPOOL |
none | false |
boolean | Whether workers keep the exchange partitions addressed to them on their own disk, so producers upload straight to the consuming worker and the coordinator relays nothing. | worker | true (chart value workers.exchange.spool) |
KAVEON_EXCHANGE_SPOOL_ROOT |
none | the system temporary directory | directory path | Root of the disk exchange store on whichever role spools. | coordinator or worker, whichever spools | /state/exchange on both roles (chart) |
KAVEON_EXCHANGE_RECLAIM_ON_START |
none | false |
boolean (true/false, 1/0, on/off) |
On a dedicated spool root, remove exchange directories left by the previous process before accepting traffic. Enable this for a single-owner coordinator or worker volume; do not enable it on a root shared by multiple live Engine processes. | coordinator or worker, whichever spools | true in the Helm chart |
KAVEON_EXCHANGE_DISK_LIMIT_BYTES |
none | 10737418240 (10 GiB) | bytes | The disk exchange store's total on the node, across queries. Must be positive. | coordinator or worker, whichever spools | workers 8589934592 (8 GiB); coordinator 25769803776 (24 GiB, kept sized for its 32 GiB PVC although its spool is off); chart values <role>.exchange.diskLimitBytes |
KAVEON_EXCHANGE_QUERY_DISK_LIMIT_BYTES |
none | 8589934592 (8 GiB) | bytes | One query's share of the disk exchange store. Must be positive and is expected to be at most the store's total. | coordinator or worker, whichever spools | workers 6442450944 (6 GiB); coordinator 17179869184 (16 GiB); chart values <role>.exchange.queryDiskLimitBytes |
KAVEON_IPC_SPOOL_ROOT |
none | the system temporary directory | directory path | Where a consumer spools a received Arrow IPC payload before decoding it (transport.rs). The directory must exist. |
worker (final and join stages), coordinator (result collection) | /state on the workers (chart); the coordinator uses the default |
KAVEON_EXCHANGE_TOKEN |
exchange.token |
none (required for a cluster) | bearer token | The credential workers and the coordinator present on /v1/task, /v1/exchange/*, /v1/node/heartbeat and /v1/internal/*. Must be nonempty and distinct from every other token. |
coordinator, worker | from the kaveon-engine-auth secret |
KAVEON_STAGE_RETRY_LIMIT |
none | 2 | re-executions per stage per query | How many times one stage's finished output may be produced again for one query because a worker holding its consumers' exchange spools was lost. A lost worker's tasks move to survivors and the producers of every consumer partition whose spool was on it run again as the next attempt (down to the scans when their own inputs were released); beyond the limit the query fails, naming the lost worker and the stage. 0 keeps task retry and refuses stage re-execution. |
coordinator | not set (default 2; not yet measured on the cluster) |
Fixed exchange limits that are not settings: a streamed output partition is at most 8 GiB in 4 MiB chunks (2048 chunks); a received payload is at most 8 GiB; the process-wide IPC spool holds at most 12 GiB at once; a task is attempted at most 3 times (failures of its own; an attempt created by a worker loss is not one).
| Name | Config key | Default | Unit | What it bounds | Applies to | AKS qualification value |
|---|---|---|---|---|---|---|
KAVEON_DATA_DIR |
storage.data_dir |
none | directory path | A local directory whose Parquet files, directories of Parquet files and Delta tables bootstrap the kaveon catalog on first start. |
coordinator, worker | not set |
KAVEON_CATALOG_DIR |
storage.catalog_dir |
none | directory path | A directory of <name>.toml catalog files bootstrapped on first start. |
coordinator, worker | not set |
KAVEON_CATALOG_DATABASE_PATH |
storage.catalog_database_path, catalog.database_path |
kaveon-catalog.db in the working directory |
file path | The durable catalog store (SQLite). Its parent directory is created. | coordinator, worker | /state/catalog/kaveon-catalog.db |
KAVEON_CATALOG_ADMIN_TOKEN |
catalog.admin_token |
none | bearer token | The service credential confined to /v1/catalog/* definition writes. Nonempty and distinct when set. |
coordinator | from the kaveon-engine-auth secret |
KAVEON_STATISTICS_AUTO_REFRESH |
none | true |
boolean | Whether the coordinator refreshes a table's statistics in the background when planning observes a source version newer than the one on record (files added to a full document folded in; a removal or a metadata-only document recomputed at the document's depth; one refresh per table at a time). Off, statistics change only through ANALYZE; a stale record still costs a plan and never answers a statement. The same knob governs the cube's refresh (added files folded in; a removal re-derived from the per-file partials, or rebuilt when a distinct count is declared). |
coordinator | not set (default) |
KAVEON_CUBE_MAX_CELLS |
none | 1000000 |
positive integer | The most cells a table's cube may hold: a declared shape whose planned cube (the caps' products over its groupings) exceeds it is refused, and a build or refresh that exceeds it fails. The encoded document is bounded with it, at 1 MiB plus 256 bytes per cell of the limit, and the per-file partials at eight times the limit in cells. | coordinator | not set (default) |
KAVEON_RAW_GROUP_EXCHANGE |
none | false |
1, true, on to enable |
Partitions a grouped aggregate's exchange by the group columns themselves rather than by the encoded aggregate-state key. Read by both the planner and the fragment executor, so it must hold the same value on the coordinator and every worker. | coordinator, worker | not set (default) |
KAVEON_COALESCE_PARTIAL_ROWS |
none | unset | rows | Opt-in Arrow batch coalescing for multi-key, high-cardinality pass-through partials. Several exact pass-through batches are concatenated before exchange consumption; one-key pass-throughs do not use it. Values below 2 or invalid values disable it. | worker | unset; qualify per workload |
KAVEON_PARTIAL_ROUND_ROBIN |
none | unset | 1, true, on to enable |
Opt-in round-robin slicing for multi-key partial aggregates. Local lanes merge duplicate keys at the final stage, avoiding the source-side hash partition and Arrow take copies. Other operators are unchanged. |
worker | unset; qualify per workload |
KAVEON_DIRECT_GROUPED_EXCHANGE |
none | unset (off) | exactly 1 enables it; any other value is off |
Routes a grouped partial's canonical Binary group_keys frame straight through the exchange. The final merge's equality parser reads the same bytes, so both the Arrow row conversion and the later ThreadSelector hash are skipped. Applies only where the source is threaded and the partial exposes a Binary group_keys field; the established text path remains the fallback for every other caller. |
worker | unset (off); qualify per workload |
KAVEON_ZERO_COPY_SELECTED_MERGE |
none | unset (off) | exactly 1 enables it; any other value is off |
Lets a selected final merge take its input without copying, on the HybridFinalMerge path that already carries a worker selection. Only reached when a selection is present. |
worker | unset (off); qualify per workload |
KAVEON_SCAN_PARTITIONS_PER_WORKER |
none | 1 |
1-16 | How many scan partitions are scheduled per compatible worker. A single large Parquet file is one task at the default, so one worker decodes all of it however many are in the cluster; above one, the file is split by row groups and its decode and partial aggregation stay concurrent. Values outside the range fall back to the default. | coordinator | not set (default) |
KAVEON_EXCHANGE_PARTITIONS |
none | the worker count | 1-64 | Destination partitions for a distributed aggregate's exchange. Scan stages may deliberately carry more tasks than the merge stage, so raising scan parallelism does not multiply the grouped state copied across the exchange. Defaults to the worker count, which preserves the original graph shape. Values outside the range fall back to that default. | coordinator | not set (default) |
KAVEON_EXCHANGE_COMPRESSION |
none | disabled | lz4, lz4_frame, 1, true |
Enables LZ4-framed Arrow IPC for exchange payloads. This reduces transfer and spool volume on wide grouped states at the cost of CPU; leave unset for same-host low-latency profiles until qualified. | coordinator, worker | unset |
KAVEON_USE_UTF8_VIEW |
none | unset | set to any value to enable | Reads Parquet string columns as Arrow Utf8View rather than Utf8. Presence is what counts, not the value. |
worker, coordinator | not set |
KAVEON_FRAGMENT_LISTING_MAX_FILES |
none | 10000 |
files | The largest directory-table listing the coordinator carries inside the fragments (the pruned file set and per-task assignment, wire version 6); over it the fragment carries the listing's digest only and each task lists, prunes and verifies the digest itself. | coordinator | not set |
KAVEON_DIFF_ONLY |
none | unset | differential-case name | Test-harness selector used by the server differential corpus to run one named case instead of the full sweep. It is intended for focused local qualification and is not a runtime execution setting. | test harness only | not set |
KAVEON_PRODUCT_TRANSACTIONS_ENABLED |
product_transactions.enabled |
false |
boolean | Whether the coordinator opens the product transaction store (native catalog commits, DML). Coordinator only. | coordinator | chart value productTransactions.enabled; enabled on the live coordinator per the 2026-09-10 Codex response |
KAVEON_PRODUCT_STORAGE_MODE |
product_transactions.storage_mode |
adls |
adls or local |
Where the product store commits. | coordinator | adls |
KAVEON_PRODUCT_ADLS_ACCOUNT |
product_transactions.account |
empty (required when enabled with adls) |
account name | The ADLS Gen2 account of the product store. | coordinator | the qualification account (kvtesticmwwliihpppo since the 2026-09-14 move to westus2; kvtestegmf6oweugsno was the eastus account), chart value productTransactions.account |
KAVEON_PRODUCT_ADLS_CONTAINER |
product_transactions.container |
empty (required when enabled with adls) |
container name | The container of the product store. | coordinator | product-transactions |
KAVEON_PRODUCT_ADLS_PREFIX |
product_transactions.prefix |
kaveon/product-catalog |
object prefix | The prefix under which the product store commits. Must be nonempty when enabled. | coordinator | kaveon/product-catalog |
KAVEON_PRODUCT_LOCAL_PATH |
product_transactions.local_path |
/var/lib/kaveon/product-transactions |
directory path | The product store's directory in local mode. |
coordinator | not applicable |
KAVEON_AZURITE_CONTAINER |
none | kaveon-product |
container name | Overrides the blob container used by the ignored Azurite conditional-commit contract test. Test-only; production ADLS commits use KAVEON_PRODUCT_ADLS_CONTAINER. |
storage test harness | not applicable |
KAVEON_LATE_MATERIALISATION |
none | auto |
auto, always, never (on/off accepted) |
Whether a scan over object storage runs the evaluable part of its predicate inside the Parquet decoder as a row filter (the predicate's columns decoded first, the rest of the projection only for the rows that survive; pages the selection never touches are skipped when the file carries an offset index). auto applies it when the remaining projection holds at least 4x the compressed bytes of the predicate's columns, or when the object is held in the full-object cache; otherwise the decoder lanes filter decoded batches. always and never override the ratio. Local Parquet files always use the row filter. Unrecognised values are auto. |
worker, coordinator | not set |
AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE, AZURE_AUTHORITY_HOST |
none | none | strings | Workload identity for the product store's ADLS commits (adls_commit.rs) and, through the object store's from_env, for ADLS scans. Set by the AKS workload identity webhook. |
coordinator (commits), worker and coordinator (scans) | injected by the kaveon-engine service account |
Fixed storage limits that are not settings: decoder lanes are capped at 4 per scan; the late-materialisation byte ratio is 4; the full-object cache admits objects up to 64 MiB and holds 256 MiB per process; the decoded-batch cache holds 256 MiB per process; a Delta log replay reads at most 64 MiB of commit JSON; Iceberg metadata is capped at 64 MiB.
| Name | Config key | Default | Unit | What it bounds | Applies to | AKS qualification value |
|---|---|---|---|---|---|---|
| (first argument) | file path | /etc/kaveon/config.toml |
path | The configuration file. Missing is not an error; every key then comes from the environment or the default. | coordinator, worker | not used; everything is environment |
KAVEON_NODE_ID |
node.id |
a random UUID per start | string | The node's identity in the cluster and in task ownership. | coordinator, worker | the pod name |
KAVEON_ENVIRONMENT |
node.environment |
production |
string | The environment name reported on /v1/cluster and every query record. |
coordinator, worker | aks-test |
KAVEON_COORDINATOR |
node.coordinator |
true |
boolean | The role: true serves statements, false executes tasks and heartbeats to the coordinator. |
both | true on the coordinator StatefulSet, false on the workers |
KAVEON_HTTP_PORT |
http.port |
8080 | port | The listening port. | both | 8080 |
KAVEON_BIND_HOST |
none | 127.0.0.1 |
IP address | The listening address. A non-loopback address requires TLS, KAVEON_TLS_PROXY_BOUNDARY=true, or insecure development mode. |
both | 0.0.0.0 |
KAVEON_DISCOVERY_URI |
discovery.uri |
http://localhost:8080 |
URI | Where a worker finds the coordinator for heartbeats and where the coordinator publishes catalog snapshots. | worker | the coordinator service URI over HTTPS |
KAVEON_ADVERTISED_URI |
discovery.advertised_uri |
none: http(s)://127.0.0.1:<port> |
URI | The address other nodes use to reach this one (task and exchange traffic). | both | the pod's DNS name |
KAVEON_TLS_CERT_PATH, KAVEON_TLS_KEY_PATH |
none | none | file paths | Serve HTTPS; both or neither. | both | /etc/kaveon/tls/tls.crt, /etc/kaveon/tls/tls.key |
KAVEON_TLS_PROXY_BOUNDARY |
none | unset | true |
Allows a non-loopback plaintext bind behind a network-isolated TLS proxy. | both | not set |
KAVEON_INSECURE_DEVELOPMENT |
security.insecure_development (JSON) |
false |
boolean | Development mode: plaintext external binding and relaxed credential checks. Never set in a deployment. | both | not set |
KAVEON_CONFIG_ENV_FALLBACK |
none | false |
boolean | If the mounted config file is malformed, ignore it and load defaults plus environment settings. Requires KAVEON_INSECURE_DEVELOPMENT=true or KAVEON_TLS_PROXY_BOUNDARY=true; intended for legacy ACA mounts only. |
both | set only during controlled ACA compatibility rollout |
KAVEON_SECURITY_JSON |
the whole SecurityConfig |
none (no principals: nothing can submit) | JSON (TOML accepted only for legacy fallback) | principals (token, principal, role: reader, analyst, admin), bridge_token, entra, studio_url, insecure_development, and the legacy resource_groups list (name, principals with one optional * catch-all, max_running, max_queued, queue_timeout_ms), still accepted and translated into resource groups at start when nothing else configures them (see Governance). Validated on start; tokens must be nonempty and distinct. A malformed value is fatal unless the explicit config environment fallback is enabled with insecure development; that emergency path discards the malformed document and must not be used for production authentication. |
coordinator (statements), worker (its own credentials) | from the kaveon-engine-auth secret, key security.json |
KAVEON_STUDIO_URL |
security.studio_url |
none | URL | The Studio origin allowed to use the Engine UI's sign-in. | coordinator | chart value studioUrl |
KAVEON_PRINCIPAL_QUERY_LIMIT |
none | 4 | statements | The default resource group's max_concurrent when no resource-group configuration names one: statements of the default group running at once on the coordinator. Kept as the alias; before 2026-09-19 it bounded each principal separately. Must be positive. |
coordinator | not set |
KAVEON_STATE_DIR |
node.state_dir |
the directory of the catalog store (KAVEON_CATALOG_DATABASE_PATH) |
directory path | Where the coordinator keeps what must survive a restart and is not the catalog store: the durable copy of a runtime resource-group replacement (resource-groups.json) and the audit ledger (audit/). |
coordinator | not set: /state/catalog |
KAVEON_AUDIT_DIR |
audit.dir |
<state dir>/audit |
directory path | Where the audit ledger keeps its JSONL segments and the catalog cursor (Governance). | coordinator | not set: /state/catalog/audit |
KAVEON_AUDIT_RETENTION_DAYS |
audit.retention_days |
90 | days | A ledger segment is removed once every record in it is older than this; 0 turns the ledger off. |
coordinator | not set |
KAVEON_AUDIT_SEGMENT_BYTES |
audit.segment_bytes |
67108864 (64 MiB) | bytes | The size at which a ledger segment is closed and the next started; at least 1 MiB. | coordinator | not set |
KAVEON_RESOURCE_GROUPS |
[resource_groups] section ([[resource_groups.groups]], [[resource_groups.selectors]], [resource_groups.demo]) |
none: the durable runtime copy, the section, the legacy list, else one built-in default group |
file path (JSON, or TOML by extension) | The resource groups and selectors (groups, selectors, demo at the top level; the keys and bounds are in Governance). Validated on start; a group over the admission limit, without a default, a selector naming an unknown group, or a rate without demo.enabled refuses to start. PUT /v1/admin/resource-groups writes back to this file. |
coordinator | not set; the chart renders it from resourceGroups when that block is enabled |
One switch on each side, both off by default so a self-hosted install is unaffected. Neither is read by the Engine as an environment variable.
| Where | Key | Default | What it does |
|---|---|---|---|
| API | KAVEON_DEMO_MODE (chart value api.demoMode) |
false |
Every mutating platform route — datasets, charts, dashboards, saved queries, catalog registration, DLM curation, settings — answers 403 demo_read_only for any role below Admin; viewing stays; per-user preferences (favorites, pins, theme, recents, the user's own history) stay; SQL Lab and the DLM stay, with submitted SQL confined to one read statement (SELECT, WITH, SHOW, DESCRIBE, EXPLAIN — DDL, DML, CALL, ANALYZE, OPTIMIZE and SET SESSION are refused with the same code). One application-level dependency in api/main.py. |
| Engine | demo.enabled in the resource-group document (chart value resourceGroups.document.demo.enabled) |
false |
Enables a group's rate — the per-principal quota of live statements over a rolling window, admins exempt, counted from the audit ledger so it survives a restart — and GET /v1/quota. Off, a rate is refused at validation. See Governance. |
| Name | Config key | Default | Unit | What it bounds | Applies to | AKS qualification value |
|---|---|---|---|---|---|---|
KAVEON_RESULT_QUERY_DISK_LIMIT_BYTES |
none | 268435456 (256 MiB) | bytes | One paged result's disk on the coordinator (result_delivery: paged: the CLI's --paged and the shell's page reads, SQL Lab's streamed statements). A statement whose pages would exceed it fails with query result disk quota exceeded (… MiB); raise KAVEON_RESULT_QUERY_DISK_LIMIT_BYTES on the coordinator, or narrow the result. Must be positive. |
coordinator | not set (default); the local Compose stack sets 2 GiB for its 504M-row lake |
KAVEON_RESULT_DISK_LIMIT_BYTES |
none | 1073741824 (1 GiB) | bytes | Every paged result's disk together, on the coordinator; a page that would exceed it fails the statement naming the setting. Must be at least the query limit. Results expire after the store TTL (below). | coordinator | not set (default); the local Compose stack sets 4 GiB |
KAVEON_RESULT_CACHE_BYTES |
result_cache.bytes |
268435456 (256 MiB); 0 disables the cache |
bytes | The coordinator's budget for complete results of finished statements, evicted least-recently-used by bytes. A result larger than an eighth of the budget is never kept. Workers keep nothing whatever the value. | coordinator | not set (default) |
KAVEON_RESULT_CACHE_TTL_SECONDS |
result_cache.ttl_seconds |
600 | seconds | How long a cached result may be served. Must be positive when the cache is enabled. | coordinator | not set (default) |
A result is keyed by the statement text (trimmed, whitespace collapsed and
letters lowercased outside string literals and quoted identifiers), the
catalog and schema, the published catalog snapshot identity, the Delta
versions the planner pinned, and the request's time zone. A catalog publish
clears every entry; so does a committed product transaction and
DELETE /v1/cache (admin). Hits are query records with
execution: {mode: "cache", detail: "hit"} and cached_from naming the
original query; counters (hits, misses, bytes, entries,
evictions, expirations, refused) are on /v1/node and on the
coordinator entry of /v1/cluster. Per-request bypass:
settings.result_cache = false; every benchmark and qualification script
in this repository sends it.
A statement may lower four of the bounds above for itself, and choose
two behaviours (what approximate and use_statistics decide on the
knowing path is in The learning engine),
through the settings object of POST /v1/statement or leading
SET SESSION <key> = <value>; statements in the same request.
Nothing can be raised; an unknown
key or an out-of-range value is HTTP 400 INVALID_SETTING with the key
named. HTTP is stateless and there is no server-side session: a setting
lives as long as the statement it arrived with. The query record's
settings field shows what a statement set. See the
API reference for the request
shapes.
| Key | Bound | What it lowers | Where it applies |
|---|---|---|---|
query_memory_limit_bytes |
1 to the coordinator's KAVEON_QUERY_MEMORY_LIMIT_BYTES |
The statement's query memory pool on the coordinator and the admission limit of each of its tasks on the workers (each worker also caps it at its own limit). | coordinator, worker |
local_parallelism |
1 to the coordinator's configured KAVEON_LOCAL_PARALLELISM |
Aggregator threads for the statement's partial aggregates, DISTINCT and final merges; carried in the task request and capped again by each worker's own value. | coordinator, worker |
result_cache |
true or false |
false bypasses the coordinator's result cache for the statement. |
coordinator |
admission_wait_seconds |
0 to the coordinator's KAVEON_MEMORY_ADMISSION_WAIT_SECONDS |
How long the statement waits for memory admission before HTTP 429; 0 refuses at once when its pool does not fit on arrival (the pre-2026-09-17 behaviour, for a client that prefers to retry itself). Ignored when the node has no queue. |
coordinator |
approximate |
true or false, default false |
true lets the planner answer every plain COUNT(DISTINCT col) from a HyperLogLog sketch — computed over the rows, or stored in the table's statistics — exactly as APPROX_COUNT_DISTINCT(col) would, under COUNT's output name; the query record's execution.approximate states the error (1.6 % relative standard error at p = 12). Nothing else is approximated; APPROX_* functions need no setting. See Approximate aggregates. |
coordinator (planning), worker (the sketch aggregate) |
use_statistics |
true or false, default true |
false stands every answer from statistics aside: the context path for COUNT(*)/MIN/MAX and the statistics path for APPROX_* are both skipped and the rows are read (APPROX_* computes its sketch over them; exact functions scan as usual). File skipping by the statistics' bounds still applies — pruning, not answering — and statistics still cost a join. execution.detail ends with statistics bypassed when the statistics would otherwise have answered. Every benchmark script sets it beside result_cache = false: a benchmark measures the read path. |
coordinator |
None of these is a setting today; they are constants in the source, listed so that an operator knows what bounds a run. Changing one is a code change.
| Constant | Value | Where | What it bounds |
|---|---|---|---|
REMOTE_TASK_TIMEOUT |
600 s | api.rs |
One task request from the coordinator to a worker. A task that times out is not retried; finishing the query cancels its orphaned tasks on the workers. |
HEARTBEAT_INTERVAL |
10 s | cluster.rs |
How often a worker heartbeats to the coordinator. |
NODE_EXPIRY |
30 s | cluster.rs |
A worker with no heartbeat for this long leaves the cluster view. |
WORKER_LOSS_MISSED_HEARTBEATS, WORKER_PROBE_TIMEOUT |
2 intervals (20 s), 5 s | cluster.rs, api.rs |
When a running query treats a worker as lost: a refused or reset connection to it (the task call or a /v1/node probe after a retryable task failure), or a heartbeat lapsed by two intervals with a probe unanswered within 5 s. A worker that answers the probe is not lost, whatever its task said. |
| Result store TTL | 900 s | results.rs |
How long paged results stay readable. |
| Disk exchange TTL | 900 s | disk_exchange.rs |
How long an exchange partition stays on disk after its query. |
| Cleanup loop | 30 s | main.rs |
How often expired results and exchange partitions are removed and the audit ledger's retention is applied. |
| Graceful shutdown | 30 s | main.rs |
On SIGTERM or Ctrl-C the listener closes, in-flight requests get this long to finish, then the audit ledger drains and the process exits. |
| Entra JWKS cache | 3600 s, refreshed no more than every 60 s, fetched with a 5 s timeout | entra.rs |
The signing keys used to validate Entra bearer tokens. |
Resource group max_queue_wait_seconds |
per group (default 60) | resource_groups.rs, api.rs |
How long a statement waits for its group's slot, its group's share and the node's pool together before HTTP 429; one wait, the shortest of the group's, the node's and the request's. |
Other fixed limits: query history keeps 100 records; inline (unpaged) results are capped at 16 MiB; the paged result store writes 4 MiB pages of at most 1000 rows (its per-query and per-process disk are settings, above); the catalog replica a worker downloads is at most 16 MiB; the worker task-reply cache holds 512 MiB per process; the in-memory exchange buffer (when no node spools) holds 512 MiB and 1024 exchanges.
These variables are consumed only by repository test binaries; the Engine runtime does not read them. They are for reproducing a focused qualification case and must not be set in a deployment.
| Name | Default | What it sets |
|---|---|---|
KAVEON_DIFF_ONLY |
unset | The kaveon-server differential-test case name to run exclusively (for example, correlated_scalar_ordered_offset_limit). Unset runs the complete differential case list. |
These are read by the kaveon client (engine/crates/cli/src/args.rs,
auth.rs, theme.rs), not by the server; the
CLI guide describes them. Each variable has a
flag that overrides it; the defaults file (KAVEON_CONFIG) sits between
the two: a flag beats the file, the file beats the built-in default.
| Name | Default | What it sets |
|---|---|---|
KAVEON_CONFIG |
~/.kaveon_config when it exists |
The key=value defaults file. Allowed keys: server, catalog, schema, user, source, client-tags, auth, ca-cert, timeout, output-format, output-format-interactive, history-file, editing-mode, pager, theme, width, row-limit. SQL and tokens are refused. |
KAVEON_ACCESS_TOKEN |
none | The Engine bearer token for unattended use; --access-token overrides it. Without either, --auth decides (Azure CLI login, Microsoft device sign-in, or none). |
KAVEON_CA_CERT |
none | A PEM CA bundle trusted for the coordinator's TLS certificate (--ca-cert). Never applied to Microsoft sign-in. |
KAVEON_HISTORY_FILE |
%APPDATA%\kaveon\history on Windows, ~/.kaveon_history elsewhere |
The shell's history file (--history-file; --no-history disables it). |
KAVEON_PAGER |
none | An external pager for human-readable output when a script or the line-editor fallback prints to a terminal (--pager; empty disables). The shell pages results itself. |
KAVEON_API_URL |
none | The Kaveon platform API the shell's .ask sends questions to (--api overrides it); the DLM answers there, not on the Engine. |
KAVEON_API_TOKEN |
none | The bearer token .ask presents to the platform API. |
NO_COLOR |
unset | Set to anything, the client prints without colour, the same as --theme mono; TERM=dumb and output that is not a terminal have the same effect. |
Client flags without a variable, with the value the code applies:
| Flag | Default | Bound | What it sets |
|---|---|---|---|
--timeout |
24 h | greater than zero; seconds, 30s or 2m |
The HTTP timeout of one statement request. POST /v1/statement returns when the statement finishes, so this is the longest a statement may take before the client reports a timeout; it does not stop the statement on the coordinator. Metadata calls keep a fixed 30 s. --client-request-timeout is an alias. |
--row-limit |
1000 | 1 to 10000 | Rows a shell query without a top-level LIMIT shows; .limit changes it in the session. Never applied to -e, -f or piped input. |
--theme |
dark |
dark, light, mono |
The accent colour (Kaveon blue, darker on light) or no colour. |
--no-header |
off | flag | Skips the session header the shell prints after connecting. |
--width |
the terminal's width, else 120 | a positive column count | The width result tables are fitted to; string columns are narrowed with … to fit. |
--paged |
off | flag | Scripts fetch results in pages from the coordinator's result store instead of inline, so a result over 16 MiB does not fail. |
KAVEON_PARALLEL_SQL_REGRESSION_CHILD is set by one server test to mark
its child process and is not a setting.