Post-install configuration
Once the chart has installed and you have signed in as the first administrator (see Install with Helm), most day-to-day configuration moves into the admin console rather than back into a values file. This page is the map of what still lives where.
Release-wide settings
Section titled “Release-wide settings”A few chart values feed many components. Set each once; a component’s own value, when you set it, wins.
| Value | Default | What it fills where that value is empty |
|---|---|---|
global.publicUrl | empty | The origin browsers open, for example https://elitea.example.com (a scheme, a host and an optional port; no path). It fills main.env.DEPLOYMENT_URL; main.env.OIDC_REDIRECT_URI as <publicUrl>/auth/oidc/callback, when main.env.OIDC_ISSUER_URL is set; the authentication document’s public_origin, when the chart renders a document; llmGateway.env.GATEWAY_SELF_LLM_ORIGINS as <publicUrl>/llm,http://elitea-main:8080/llm; worker.runtime.publicBaseUrl; worker.runtimeSession.expectedIdentity as spiffe://<host>/ns/<release namespace>/sa/agent-worker; and the host of every main.ingress.hosts and tls[].hosts entry, when that list is empty. |
global.trustedProxyCidrs | [] | The proxies whose X-Forwarded-For elitea-main believes. It fills main.env.ELITEA_TRUSTED_PROXY_CIDRS (comma-joined) and the authentication document’s trusted_proxy_cidrs. On GKE: the pod CIDR, 35.191.0.0/16 and 130.211.0.0/22. |
global.otelEndpoint | empty | An OTLP/HTTP collector outside the chart. See Observability. |
certManager.issuers.internal | elitea-internal-ca, kind empty | The issuer of the LLM gateway’s, DeepWiki’s and Inventory’s mTLS Certificates (*.mtls.issuerRef). |
certManager.issuers.runtime | elitea-runtime-ca, kind empty | The issuer of elitea-vector’s and Qdrant’s Certificates, the DeepWiki and Inventory callback client certificates and the egress proxy’s audit certificate. |
certManager.issuers.create | false | true: the chart makes both, namespaced (see below). |
An empty kind means ClusterIssuer, as before, or Issuer when create is true. With create: true the chart renders, in Argo CD wave -15: a self-signed Issuer, a CA Certificate and the elitea-internal-ca Issuer over it (ECDSA P-256, duration 43800h, renewBefore 8760h); and the elitea-runtime-ca Issuer over the existing Secret certManager.issuers.runtime.caSecretName. The chart never generates the runtime CA: the worker certificate and elitea-main’s runtime listeners are signed by it, so a new CA would fail every handshake. With externalSecrets on, that Secret is an ExternalSecret too (<caSecretName>/tls.crt and tls.key, or runtime-ca.crt and runtime-ca.key with externalSecrets.sharedProperties). create: true with a ClusterIssuer kind is refused.
Placeholders. The chart refuses to render while any value still holds a <...> placeholder of an example values file (values-gke.yaml has several), and the message lists every one by its path.
Shared secret properties. With externalSecrets.remoteKey (one flat JSON secret), externalSecrets.sharedProperties: true reads the values that several Secrets carry from one property each: runtime-ca.crt, runtime-ca.key, command-signing-keyring.json and gateway-identity-secret. A key’s own property still wins. deploy/scripts/mint-secrets.sh mints that JSON for a new install; see Deploy on GKE with Argo CD.
Identity: OIDC, SAML, SCIM
Section titled “Identity: OIDC, SAML, SCIM”Configure identity providers under Configuration › Authentication in the admin console — see Authentication for the click-through. What matters at the deployment level:
- Sign-in is OIDC or SAML. The local username/password (Form) sign-in is off by default:
main.env.ELITEA_FORM_LOGIN_ENABLEDmust be"true"for the Form users file to be a sign-in path. With it off, the authentication document is still read (the gateway edge and the runtime depend on it), but no Form login page is mounted and no configured password is accepted. Every Form user needs a real address (email, orattributes.email); one without is refused at sign-in. Seedocs/UPGRADING.mdin the platform repository. - The first global admin is a chart/environment setting, not a console one —
identity.initial_global_adminsin the auth document, ormain.env.ELITEA_INITIAL_GLOBAL_ADMINS. See the Helm install guide. - An OIDC-only install now gets the configuration plane. Before, only a Form authentication document (
ELITEA_AUTH_CONFIG_FILE) composed the principal validator the configuration write path needs; nowenv.OIDC_ISSUER_URLalone composes it too, as long asELITEA_AI_PROJECT_IDis set. A deployment with no authentication at all is still refused, in both the chart and the binary. - SCIM provisions accounts and groups at
/api/v2/scim/v2. It authenticates with a dedicated SCIM client credential (a bearer secret, or OAuth2 client credentials at/api/v2/scim/oauth/token), not with a personal access token. Create the client and bind groups to project roles in the console (see Authentication).ELITEA_SCIM_ACCESS_TOKEN_TTLsets the access token lifetime (default1h).
The first global administrator
Section titled “The first global administrator”A fresh database seeds only dev@elitea.ai. On a single-sign-on deployment, this account has no password. Set identity.initial_global_admins or the equivalent environment variable before you rely on the admin console.
E-mail: SMTP bootstrap defaults
Section titled “E-mail: SMTP bootstrap defaults”SMTP_HOST, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, SMTP_TLS, EMAIL_FROM, EMAIL_REPLY_TO and PUBLIC_BASE_URL are a default layer, not the whole configuration. Admin → E-mail writes a second layer into the database, and internal/emailsettings merges the two field by field on every send — the database wins where it has a value.
Set the bootstrap defaults
Ship
EMAIL_FROMandPUBLIC_BASE_URLat minimum throughmain.env;SMTP_PASSWORDbelongs in thesecrets:block (a Secret), never as a plaintext parameter.Let an administrator name the relay
A change in the console needs no restart or re-sync — the merge runs per message.
Check what resolved
Terminal window curl -s -H "Authorization: Bearer $ADMIN_PAT" \https://elitea.example.com/api/v2/admin/email/administration | jq.settingsis what the console stored,.effectiveis the merged document the next message uses,.sourcesnamesdatabase/environment/unsetper field, and.configured/.reasonsay whether a message can be sent.
Egress allowlists
Section titled “Egress allowlists”Separate allowlists guard separate outbound paths:
Names the hosts a saved provider credential’s api_base may point at. It is the floor: the gateway also reads egress_allowlist rows from gateway.governance_config (edit them at Admin → LLM Governance → New entry, type Egress allowlist, no re-sync needed) and enforces the union. An authored row can only add a destination — nothing an admin authors can withdraw a host the chart named. For a host that a running deployment needs, add a governance entry first; change this variable for hosts that every deployment of the configuration needs.
When the list refuses a host, Test connection names the host and both places to add it. See When the egress allowlist refuses a provider. Vertex AI needs its regional host, <location>-aiplatform.googleapis.com, and the token host oauth2.googleapis.com.
One grammar for both sources: a bare host, host:port, a *.domain wildcard, or a CIDR block. The first entry anywhere turns the restriction on — with none in either source, a credential may name any public host.
A private endpoint needs its address named, not only a hostname — bifrost’s SSRF-safe dialer refuses RFC 1918 and loopback destinations unless an entry explicitly names a private address or block, because the gateway never resolves a name before deciding (that would reopen the DNS-rebinding race the allowlist exists to close). Link-local addresses (169.254.0.0/16, fe80::/10 — cloud metadata endpoints) are refused no matter what the allowlist says.
GET /governance/status on the gateway (proxied at GET /api/v2/admin/gateway/status, and shown on Admin → LLM Proxy → Status) reports the merged list by source and whether a private destination is actually reachable.
Governs where a tenant-created webhook may dial. Unset is the safe default: every RFC 1918, ULA and loopback destination is refused, both when a webhook is created and again at dial time (the destination is re-resolved, not trusted from create time). Set it only to let webhooks reach a private receiver you control; link-local and multicast addresses are refused unconditionally regardless of this variable.
This variable is not a named key in values.yaml — set it like any other elitea-main environment variable:
--set-string main.env.ELITEA_WEBHOOK_EGRESS_ALLOWLIST="10.0.0.0/8"Governs where elitea-main may dial for a Remote MCP server: Load Tools, the OAuth and client-registration proxies, and the authorization metadata those servers name. It uses the same grammar and the same split as the webhook allowlist. Unset refuses every loopback, RFC 1918 and ULA destination, and each connection re-resolves the host before it dials. Name a private range (for example 10.0.0.0/8) to let users reach MCP servers on your internal network. Link-local and multicast addresses stay refused whatever this variable says.
--set-string main.env.ELITEA_MCP_EGRESS_ALLOWLIST="10.0.0.0/8"Governs the public hosts an agent’s tools reach from the worker: web fetches, toolkit clients, OpenAPI tools, remote MCP servers, index runs and the workspace pull-request push. It is a console setting, not an environment variable: section worker_egress, with mode (open, the default, or allowlist) and allowlist (at most 512 entries, the same grammar as above). A project adds its own entries with a worker_egress project configuration (at most 256). In allowlist mode each run may reach the platform’s entries, its project’s entries and the hosts its own toolkits and MCP servers are configured with. Runs under the governed credential profile always use allowlist mode.
The worker and the egress proxy report the hosts each run reached and was refused. Main keeps those summaries in elitea_runtime.egress_run_summaries for ELITEA_EGRESS_AUDIT_RETENTION_DAYS days (default 30, at most 365), and writes one audit event per run turn. The same panel lists them, so you can seed the allowlist before you switch.
--set-string main.env.ELITEA_EGRESS_AUDIT_RETENTION_DAYS="90"See Least privilege and trust for what is enforced and the evidence it produces.
Budgets need GATEWAY_NATS_URL
Section titled “Budgets need GATEWAY_NATS_URL”Admin → Budgets writes spend-ceiling rows, but the LLM gateway is what enforces them, through a NATS JetStream counter — GATEWAY_NATS_URL names that server. In Kubernetes the chart derives it from the top-level nats block as tls://elitea-nats.<namespace>.svc.cluster.local:4222, in the platform’s own namespace, and mounts the gateway’s NATS client certificate beside it; an override must also be tls:// and carry no credential.
Worker implementation: python (default) or rust
Section titled “Worker implementation: python (default) or rust”worker.implementation selects which agent worker image the chart runs; the values are not interchangeable and the chart handles the difference rather than the operator.
Every catalogued toolkit type and every internal chat-agent tool is available, at the cost of the larger interpreter/dependency image. This is the default in both the Helm chart and standalone-stack.sh.
A smaller, faster process with the platform’s native agent runtime (checkpointing, step-limit enforcement) and no Python dependency surface — but, as of this release, 18 toolkit types are unimplemented (ado_boards, ado_plans, ado_repos, ado_wiki, aha, bitbucket, confluence, figma, plain gitlab, jira, PowerPoint, qtest, TestIO, TestRail, XRAY Cloud, Zephyr Enterprise, Zephyr Essential, Zephyr Scale) and six internal chat-agent tools are skipped with a visible notice instead of run (Image creation, Data Analysis, Elitea MCP Tools, Planner, Swarm Mode, Smart Tools Selection). Every tile still shows, greyed with a reason, rather than disappearing.
runtime.json — the worker’s own configuration document — is byte-identical either way; only the process and its capability surface differ.
Object storage and artifacts
Section titled “Object storage and artifacts”main.env.STORAGE_BACKEND / STORAGE_CONTAINER point at an S3-compatible bucket. It must exist before the first sync — the readiness probe tolerates a missing bucket, but the very next boot step (setting the bucket’s retention lifecycle) does not, so a missing bucket looks like a green install that then crash-loops. objectInit.enabled: true creates it for a self-hosted S3-compatible endpoint you administer directly (RustFS, MinIO); a managed cloud object store almost always withholds CreateBucket from an application-scoped credential, so create it out of band there.
DeepWiki and Inventory: disk needs
Section titled “DeepWiki and Inventory: disk needs”Both are the same pattern — a Go subapp-host serving the SPI, reaching an engine sidecar over a Unix socket (for DeepWiki the Rust-native elitea-deepwiki-engine-native image, for Inventory the Rust-native elitea-inventory-engine image). Both are on by default, and each is one switch: deepwiki.enabled / inventory.enabled. The chart derives elitea-main’s side from the provider’s block — ELITEA_DEEPWIKI_ENABLED / ELITEA_INVENTORY_ENABLED, the git allowlist (copied from deepwiki.env / inventory.env), the client-certificate paths and mounts, and the platform gRPC target — so the two halves cannot drift apart. A main.env value that agrees is kept; one that disagrees fails the render with the switch to set instead. To leave either out, set enabled: false explicitly. The one value the chart cannot default is the git allowlist (ELITEA_DEEPWIKI_GIT_ALLOWLIST, ELITEA_INVENTORY_GIT_ALLOWLIST): the render lists it with every other missing value in one message. Their callback client certificates (elitea-deepwiki-callback-client, elitea-inventory-callback-client) are issued by cert-manager from the elitea-runtime-ca issuer, and their identity Secrets have fixed names (elitea-deepwiki-secrets, elitea-inventory-secrets, key identity-secret).
Each provider’s scratch space (deepwiki.scratch 8Gi, inventory.scratch 20Gi by default) is ephemeral clone/index space, not durable storage — a wiki publishes to PostgreSQL, and a replica that dies mid-generation only loses work already being redone. ELITEA_DEEPWIKI_GIT_ALLOWLIST / the Inventory equivalent are read fail-closed by both halves (the facade and the provider); two values that disagree mean an invocation that starts and then fails.
See DeepWiki and Inventory for the product-facing side.
Observability
Section titled “Observability”Traces flow over OpenTelemetry to the chart’s own otelCollector (on by default, otel/opentelemetry-collector-contrib). The shipped pipeline exports to debug (log-only) — swap the otelCollector.config exporter for a real sink (an OTLP/HTTP endpoint, a vendor backend) before relying on traces outliving the pod. There is no bundled Langfuse or third-party APM integration.
The chart sets each component’s OTEL_EXPORTER_OTLP_ENDPOINT (elitea-main, the scheduler, the LLM gateway, DeepWiki, Inventory, elitea-vector and the worker) where you have not set it or OTEL_EXPORTER_OTLP_TRACES_ENDPOINT or OTEL_SDK_DISABLED:
global.otelEndpoint, when set;- else the bundled collector,
http://<collector fullname>:4318, whenotelCollector.enabled; - else
OTEL_SDK_DISABLED=true, so no component exports tolocalhost. The gateway does not read that variable; with no endpoint it exports nothing.
The worker has no free-form env block, so it always gets this value.
Export audit evidence to a SIEM
Section titled “Export audit evidence to a SIEM”Set any of these as main.env keys. Both endpoints empty (the default) means export is off: no relay starts, no listener opens, nothing dials out. A bad value refuses the boot. What the export does and does not guarantee is in Audit trail; the event format is in the audit event schema reference.
| Key | Default | Meaning |
|---|---|---|
ELITEA_AUDIT_EXPORT_OTLP_ENDPOINT | empty | OTLP logs receiver. For http, the collector’s base URL (/v1/logs is appended); for grpc, host:port or a URL whose scheme picks TLS (https) or plaintext (http). |
ELITEA_AUDIT_EXPORT_OTLP_PROTOCOL | http | http or grpc. |
ELITEA_AUDIT_EXPORT_OTLP_HEADERS_FILE | empty | Absolute path of a JSON object of request headers (an API key for a hosted SIEM). |
ELITEA_AUDIT_EXPORT_WEBHOOK_URL | empty | Signed webhook receiver. https, or http only when the allowlist below names the receiver. No credentials in the URL. |
ELITEA_AUDIT_EXPORT_WEBHOOK_KEYS_FILE | empty | Absolute path of the signing keys file. Required with the webhook URL. |
ELITEA_AUDIT_EXPORT_EGRESS_ALLOWLIST | empty | Same grammar as ELITEA_WEBHOOK_EGRESS_ALLOWLIST. A receiver on a private address must be named here; link-local, multicast, reserved and cloud-metadata addresses stay refused. |
ELITEA_AUDIT_EXPORT_AUDIT_EVENTS | true | Also export the admin audit trail (centry.audit_events), not only security audit events. |
ELITEA_AUDIT_EXPORT_AUDIT_EVENTS_FROM | now | now starts at the newest audit trail row; beginning replays the table on the first run. |
ELITEA_AUDIT_EXPORT_BATCH_SIZE | 200 | Events per pass, 1 to 5000. The webhook sends 100 per request. |
ELITEA_AUDIT_EXPORT_INTERVAL | 5s | Pause between audit trail passes, 1s to 1h. |
ELITEA_AUDIT_EXPORT_MAX_PERMANENT_ATTEMPTS | 5 | How many times the receiver may refuse the same batch as malformed (400, 413, 422) before it is dead-lettered. |
ELITEA_AUDIT_EXPORT_METRICS_ADDR | :9464 | Listener for the export’s Prometheus /metrics. Empty disables it. |
The webhook keys and OTLP headers are files, never environment values. Put them in a Kubernetes Secret and let the chart mount it:
kubectl -n elitea create secret generic audit-export \ --from-file=webhook-keys.json --from-file=otlp-headers.json
helm upgrade elitea ./elitea --reuse-values \ --set main.auditExport.secretName=audit-export \ --set-string main.env.ELITEA_AUDIT_EXPORT_WEBHOOK_URL=https://siem.example.com/elitea \ --set-string main.env.ELITEA_AUDIT_EXPORT_WEBHOOK_KEYS_FILE=/etc/elitea/audit-export/webhook-keys.jsonThe keys file is read at start and again every 30 seconds, so a rotated key needs no restart:
{"keys":[{"id":"2026-10","secret":"<at least 32 characters>","created":"2026-10-01T00:00:00Z"}]}To rotate, give your receiver the new key first, then list it beside the old one with a later created. Elitea signs with the newest key and names it in the X-Elitea-Key-Id header; the receiver verifies with whichever it holds. Remove the old key once nothing needs it. At most two keys are accepted.
Enterprise credential governance
Section titled “Enterprise credential governance”Off by default. main.env.ELITEA_ENTERPRISE_CREDENTIAL_GOVERNANCE_ENABLED pins every new run to a governed profile and an immutable policy revision, mounts the agent identity admin API, and can require an external Vault/OpenBao store. See Enterprise credential governance before you turn it on.
Maintenance and the banner
Section titled “Maintenance and the banner”Both are console-editable under Configuration, not chart settings: a dismissible banner with its own icon/style/message, and a maintenance mode that answers 503 with a splash screen to every caller without administration access (the admin console and authentication routes stay reachable, so the window is reversible from inside itself). See Features and configuration for the click-through.