ADR-0004: GenAI ships disabled by default
ODD Platform ships GenAI off by default — a runtime guard rejects requests until an operator sets genai.enabled and supplies the url and timeout, which have no working defaults.
Status
Accepted. Reconstructed from the codebase on 2026-05-30; the decision is live in the source today.
Context
The GenAI feature lets a user ask a natural-language question that ODD Platform forwards to an operator-supplied LLM service. That service is external, operator-owned, and has no universal default endpoint — so the feature cannot work until an operator points it at their own service. The platform needs a shipped default that is safe and inert for the operators who never configure it, while still being available to those who do.
Decision
GenAI ships disabled by default, and the feature is a thin proxy whose connection has no working defaults. The shipped application.yml sets genai.enabled: false verbatim. When disabled, the feature is enforced by a runtime guard, not by conditional bean wiring: the GenAI beans are always built, and GenAIServiceImpl checks the flag on every call — if (!genAIProperties.isEnabled()) returns an error (BadUserRequestException, "Gen AI is disabled") before any outbound request.
To turn the feature on an operator must do two things, not one: set genai.enabled: true, and supply the connection details, because the configuration has no usable defaults. GenAIProperties defaults url to null and requestTimeout to 0 — so a deployment that flips only enabled builds a client with no endpoint and a zero-minute (immediate) timeout, and fails at the first request. The defaults are deliberately inert: the platform does not guess an endpoint or a timeout.
When enabled and configured, the platform is a thin proxy: GenAIServiceImpl forwards the user's question text to the operator's URL (POST {url}/query_data with the question as the request body) and returns the service's answer. The platform does not engineer the prompt, perform retrieval-augmentation, or cache the result — those concerns belong to the operator's external service.
Consequences
An operator who installs ODD and never touches GenAI runs with the feature inert and safe — every call is rejected by the runtime guard.
📌 Enabling is a two-step the operator must complete. Setting only
genai.enabled: trueis a misconfiguration the platform accepts at startup and surfaces only at the first request (no endpoint, immediate timeout). Operators must setgenai.urlandgenai.request_timeouttogether withenabled. The GenAI feature page carries this configuration guidance and the known-limitations note; this record explains why the defaults are inert.Because the feature is a thin proxy, the security and quality of answers (prompt-injection handling, data exposure to the LLM, output filtering) are properties of the operator's external service, not of ODD Platform. The platform's responsibility ends at forwarding the question and returning the response.
The guard is at request time rather than bean-wiring time, so the GenAI beans exist even when disabled. This keeps the wiring simple (no conditional bean graph) at the cost that "disabled" is enforced by one runtime check rather than by the absence of the beans.
Evidence
odd-platform-api/src/main/resources/application.yml:18—genai.enabled: false, the explicit shipped default.odd-platform-api/.../service/genai/GenAIServiceImpl.java:37-38— the runtime guard:if (!genAIProperties.isEnabled()) { return Mono.error(new BadUserRequestException("Gen AI is disabled")); }, evaluated per request before any outbound call.odd-platform-api/.../config/properties/GenAIProperties.java—url(String) defaults tonullandrequestTimeout(int) defaults to0; there are no field initializers, so enabling without supplying these yields a non-functional client.odd-platform-api/.../service/genai/GenAIServiceImpl.java:41-47— the thin-proxy forward:webClient.post().uri("/query_data").bodyValue(Map.of("question", request.getBody()))…, returning the external service's body; no prompt construction or retrieval-augmentation in the platform.
See also
GenAI — the feature page with the operator configuration steps and the enable-without-config known limitation.
Last updated