> For the complete documentation index, see [llms.txt](https://docs.opendatadiscovery.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.opendatadiscovery.org/developer-guides/architecture-decision-log/adr-0004-genai-disabled-by-default.md).

# ADR-0004: GenAI ships disabled by default

## 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: true` is a misconfiguration the platform accepts at startup and surfaces only at the first request (no endpoint, immediate timeout). Operators must set `genai.url` and `genai.request_timeout` together with `enabled`. The [GenAI](/features/active-platform-features/genai.md) 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 to `null` and `requestTimeout` (int) defaults to `0`; 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](/features/active-platform-features/genai.md) — the feature page with the operator configuration steps and the enable-without-config known limitation.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.opendatadiscovery.org/developer-guides/architecture-decision-log/adr-0004-genai-disabled-by-default.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
